小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

linux 多線程編程

 feiyacz 2013-01-04

1.Linux“線程”

     進(jìn)程與線程之間是有區(qū)別的,不過Linux內(nèi)核只提供了輕量進(jìn)程的支持,未實(shí)現(xiàn)線程模型。Linux是一種“多進(jìn)程單線程”的操作系統(tǒng)。Linux本身只有進(jìn)程的概念,而其所謂的“線程”本質(zhì)上在內(nèi)核里仍然是進(jìn)程。

     大家知道,進(jìn)程是資源分配的單位,同一進(jìn)程中的多個線程共享該進(jìn)程的資源(如作為共享內(nèi)存的全局變量)。Linux中所謂的“線程”只是在被創(chuàng)建時 clone了父進(jìn)程的資源,因此clone出來的進(jìn)程表現(xiàn)為“線程”,這一點(diǎn)一定要弄清楚。因此,Linux“線程”這個概念只有在打冒號的情況下才是最 準(zhǔn)確的。

     目前Linux中最流行的線程機(jī)制為LinuxThreads,所采用的就是線程-進(jìn)程“一對一”模型,調(diào)度交給核心,而在用戶級實(shí)現(xiàn)一個包括信號處理在 內(nèi)的線程管理機(jī)制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)負(fù)責(zé)開發(fā)完成,并已綁定在GLIBC中發(fā)行,它實(shí)現(xiàn)了一種BiCapitalized面向Linux的 Posix 1003.1c “pthread”標(biāo)準(zhǔn)接口。Linuxthread可以支持Intel、Alpha、MIPS等平臺上的多處理器系統(tǒng)。

按照POSIX 1003.1c 標(biāo)準(zhǔn)編寫的程序與Linuxthread 庫相鏈接即可支持Linux平臺上的多線程,在程序中需包含頭文件pthread. h,在編譯鏈接時使用命令:

gcc -D -REENTRANT -lpthread xxx. c


其中-REENTRANT宏使得相關(guān)庫函數(shù)(如stdio.h、errno.h中函數(shù)) 是可重入的、線程安全的(thread-safe),-lpthread則意味著鏈接庫目錄下的libpthread.a或libpthread.so文 件。使用Linuxthread庫需要2.0以上版本的Linux內(nèi)核及相應(yīng)版本的C庫(libc 5.2.18、libc 5.4.12、libc 6)。

     2.“線程”控制

線程創(chuàng)建

進(jìn)程被創(chuàng)建時,系統(tǒng)會為其創(chuàng)建一個主線程,而要在進(jìn)程中創(chuàng)建新的線程,則可以調(diào)用pthread_create:

pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);


start_routine為新線程的入口函數(shù),arg為傳遞給start_routine的參數(shù)。

每個線程都有自己的線程ID,以便在進(jìn)程內(nèi)區(qū)分。線程ID在pthread_create調(diào)用時回返給創(chuàng)建線程的調(diào)用者;一個線程也可以在創(chuàng)建后使用pthread_self()調(diào)用獲取自己的線程ID:

pthread_self (void) ;


線程退出

線程的退出方式有三:

(1)執(zhí)行完成后隱式退出;

(2)由線程本身顯示調(diào)用pthread_exit 函數(shù)退出;

pthread_exit (void * retval) ;


(3)被其他線程用pthread_cance函數(shù)終止:

pthread_cance (pthread_t thread) ;


在某線程中調(diào)用此函數(shù),可以終止由參數(shù)thread 指定的線程。

如果一個線程要等待另一個線程的終止,可以使用pthread_join函數(shù),該函數(shù)的作用是調(diào)用pthread_join的線程將被掛起直到線程ID為參數(shù)thread的線程終止:

pthread_join (pthread_t thread, void** threadreturn);

3.線程通信

線程互斥

互斥意味著“排它”,即兩個線程不能同時進(jìn)入被互斥保護(hù)的代碼。Linux下可以通過pthread_mutex_t 定義互斥體機(jī)制完成多線程的互斥操作,該機(jī)制的作用是對某個需要互斥的部分,在進(jìn)入時先得到互斥體,如果沒有得到互斥體,表明互斥部分被其它線程擁有,此 時欲獲取互斥體的線程阻塞,直到擁有該互斥體的線程完成互斥部分的操作為止。

下面的代碼實(shí)現(xiàn)了對共享全局變量x 用互斥體mutex 進(jìn)行保護(hù)的目的:

int x; // 進(jìn)程中的全局變量
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //按缺省的屬性初始化互斥體變量mutex
pthread_mutex_lock(&mutex); // 給互斥體變量加鎖
… //對變量x 的操作
phtread_mutex_unlock(&mutex); // 給互斥體變量解除鎖


線程同步

同步就是線程等待某個事件的發(fā)生。只有當(dāng)?shù)却氖录l(fā)生線程才繼續(xù)執(zhí)行,否則線程掛起并放棄處理器。當(dāng)多個線程協(xié)作時,相互作用的任務(wù)必須在一定的條件下同步。

Linux下的C語言編程有多種線程同步機(jī)制,最典型的是條件變量(condition variable)。pthread_cond_init用來創(chuàng)建一個條件變量,其函數(shù)原型為:

pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);


pthread_cond_wait和pthread_cond_timedwait用來等待條件變量被設(shè)置,值得注意的是這兩個等待調(diào)用需要一個已經(jīng)上 鎖的互斥體mutex,這是為了防止在真正進(jìn)入等待狀態(tài)之前別的線程有可能設(shè)置該條件變量而產(chǎn)生競爭。pthread_cond_wait的函數(shù)原型為:

pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);


pthread_cond_broadcast用于設(shè)置條件變量,即使得事件發(fā)生,這樣等待該事件的線程將不再阻塞:

pthread_cond_broadcast (pthread_cond_t *cond) ;


pthread_cond_signal則用于解除某一個等待線程的阻塞狀態(tài):

pthread_cond_signal (pthread_cond_t *cond) ;


pthread_cond_destroy 則用于釋放一個條件變量的資源。

在頭文件semaphore.h 中定義的信號量則完成了互斥體和條件變量的封裝,按照多線程程序設(shè)計中訪問控制機(jī)制,控制對資源的同步訪問,提供程序設(shè)計人員更方便的調(diào)用接口。

sem_init(sem_t *sem, int pshared, unsigned int val);


這個函數(shù)初始化一個信號量sem 的值為val,參數(shù)pshared 是共享屬性控制,表明是否在進(jìn)程間共享。

sem_wait(sem_t *sem);


調(diào)用該函數(shù)時,若sem為無狀態(tài),調(diào)用線程阻塞,等待信號量sem值增加(post )成為有信號狀態(tài);若sem為有狀態(tài),調(diào)用線程順序執(zhí)行,但信號量的值減一。

sem_post(sem_t *sem);


調(diào)用該函數(shù),信號量sem的值增加,可以從無信號狀態(tài)變?yōu)橛行盘枲顟B(tài)。

    

 

4.實(shí)例

下面我們還是以名的生產(chǎn)者/消費(fèi)者問題為例來闡述Linux線程的控制和通信。一組生產(chǎn)者線程與一組消費(fèi)者線程通過緩沖區(qū)發(fā)生聯(lián)系。生產(chǎn)者線程將生產(chǎn)的產(chǎn)品送入緩沖區(qū),消費(fèi)者線程則從中取出產(chǎn)品。緩沖區(qū)有N 個,是一個環(huán)形的緩沖池。
復(fù)制代碼
#include <stdio.h>
#include
<pthread.h>
#define BUFFER_SIZE 16 // 緩沖區(qū)數(shù)量
struct prodcons
{
// 緩沖區(qū)相關(guān)數(shù)據(jù)結(jié)構(gòu)
int buffer[BUFFER_SIZE]; /* 實(shí)際數(shù)據(jù)存放的數(shù)組*/
pthread_mutex_t
lock; /* 互斥體lock 用于對緩沖區(qū)的互斥操作 */
int readpos, writepos; /* 讀寫指針*/
pthread_cond_t notempty;
/* 緩沖區(qū)非空的條件變量 */
pthread_cond_t notfull;
/* 緩沖區(qū)未滿的條件變量 */
};
/* 初始化緩沖區(qū)結(jié)構(gòu) */
void init(struct prodcons *b)
{
pthread_mutex_init(
&b->lock, NULL);
pthread_cond_init(
&b->notempty, NULL);
pthread_cond_init(
&b->notfull, NULL);
b
->readpos = 0;
b
->writepos = 0;
}
/* 將產(chǎn)品放入緩沖區(qū),這里是存入一個整數(shù)*/
void put(struct prodcons *b, int data)
{
pthread_mutex_lock(
&b->lock);
/* 等待緩沖區(qū)未滿*/
if ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait(
&b->notfull, &b->lock);
}
/* 寫數(shù)據(jù),并移動指針 */
b
->buffer[b->writepos] = data;
b
->writepos++;
if (b->writepos >= BUFFER_SIZE)
b
->writepos = 0;
/* 設(shè)置緩沖區(qū)非空的條件變量*/
pthread_cond_signal(
&b->notempty);
pthread_mutex_unlock(
&b->lock);
}
/* 從緩沖區(qū)中取出整數(shù)*/
int get(struct prodcons *b)
{
int data;
pthread_mutex_lock(
&b->lock);
/* 等待緩沖區(qū)非空*/
if (b->writepos == b->readpos)
{
pthread_cond_wait(
&b->notempty, &b->lock);
}
/* 讀數(shù)據(jù),移動讀指針*/
data
= b->buffer[b->readpos];
b
->readpos++;
if (b->readpos >= BUFFER_SIZE)
b
->readpos = 0;
/* 設(shè)置緩沖區(qū)未滿的條件變量*/
pthread_cond_signal(
&b->notfull);
pthread_mutex_unlock(
&b->lock);
return data;
}

/* 測試:生產(chǎn)者線程將1 到10000 的整數(shù)送入緩沖區(qū),消費(fèi)者線
程從緩沖區(qū)中獲取整數(shù),兩者都打印信息
*/
#define OVER ( - 1)
struct prodcons buffer;
void *producer(void *data)
{
int n;
for (n = 0; n < 10000; n++)
{
printf(
"%d --->\n", n);
put(
&buffer, n);
} put(
&buffer, OVER);
return NULL;
}

void *consumer(void *data)
{
int d;
while (1)
{
d
= get(&buffer);
if (d == OVER)
break;
printf(
"--->%d \n", d);
}
return NULL;
}

int main(void)
{
pthread_t th_a, th_b;
void *retval;
init(
&buffer);
/* 創(chuàng)建生產(chǎn)者和消費(fèi)者線程*/
pthread_create(
&th_a, NULL, producer, 0);
pthread_create(
&th_b, NULL, consumer, 0);
/* 等待兩個線程結(jié)束*/
pthread_join(th_a,
&retval);
pthread_join(th_b,
&retval);
return 0;
}
復(fù)制代碼



5.WIN32、VxWorks、Linux線程類比

目前為止,筆者已經(jīng)創(chuàng)作了《基于嵌入式操作系統(tǒng)VxWorks的多任務(wù)并發(fā)程序設(shè)計》(《軟件報》2006年5~12期連載)、《深入淺出Win32多線程程序設(shè)計》(天極網(wǎng)技術(shù)專題)系列,我們來找出這兩個系列文章與本文的共通點(diǎn)。

看待技術(shù)問題要瞄準(zhǔn)其本質(zhì),不管是Linux、VxWorks還是WIN32,其涉及到多線程的部分都是那些內(nèi)容,無非就是線程控制和線程通信,它們的許多函數(shù)只是名稱不同,其實(shí)質(zhì)含義是等價的,下面我們來列個三大操作系統(tǒng)共同點(diǎn)詳細(xì)表單:

事項(xiàng) WIN32 VxWorks Linux
線程創(chuàng)建 CreateThread taskSpawn pthread_create
線程終止 執(zhí)行完成后退出;線程自身調(diào)用ExitThread函數(shù)即終止自己;被其他線程調(diào)用函數(shù)TerminateThread函數(shù) 執(zhí)行完成后退出;由線程本身調(diào)用exit退出;被其他線程調(diào)用函數(shù)taskDelete終止 執(zhí)行完成后退出;由線程本身調(diào)用pthread_exit 退出;被其他線程調(diào)用函數(shù)pthread_cance終止
獲取線程ID GetCurrentThreadId taskIdSelf pthread_self
創(chuàng)建互斥 CreateMutex semMCreate pthread_mutex_init
獲取互斥 WaitForSingleObject、WaitForMultipleObjects semTake pthread_mutex_lock
釋放互斥 ReleaseMutex semGive phtread_mutex_unlock
創(chuàng)建信號量 CreateSemaphore semBCreate、semCCreate sem_init
等待信號量 WaitForSingleObject semTake sem_wait
釋放信號量 ReleaseSemaphore semGive sem_post

6.小結(jié)

本章講述了Linux下多線程的控制及線程間通信編程方法,給出了一個生產(chǎn)者/消費(fèi)者的實(shí)例,并將Linux的多線程與WIN32、VxWorks多線程進(jìn)行了類比,總結(jié)了一般規(guī)律。鑒于多線程編程已成為開發(fā)并發(fā)應(yīng)用程序的主流方法,學(xué)好本章的意義也便不言自明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>                                                             
#include <stdio.h>
#include <pthread.h>
void thread(void)                                                              
{                                                                              
    int i;                                                                     
    for(i=0;i<3;i++)                                                           
        printf("This is a pthread.\n");                                        
}
 
int main(void)                                                                 
{                                                                              
    pthread_t id;                                                              
    int i,ret;                                                                 
    ret=pthread_create(&id,NULL,(void *) thread,NULL);                         
    if(ret!=0){                                                                
        printf ("Create pthread error!\n");                                    
        exit (1);                                                              
    }                                                                          
    for(i=0;i<3;i++)                                                           
        printf("This is the main process.\n");                                 
    pthread_join(id,NULL);                                                     
    return (0);                                                                
}

編譯:

gcc example1.c -lpthread -o example1

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#define MAX 10
 
pthread_t thread[2];
pthread_mutex_t mut;
int number=0, i;
 
void *thread1()
{
    printf ("thread1 : I'm thread 1\n");
    for (i = 0; i < MAX; i++)
        {
            printf("thread1 : number = %d\n",number);
            pthread_mutex_lock(&mut);
            number++;
            pthread_mutex_unlock(&mut);
            sleep(2);
        }
    printf("thread1 :主函數(shù)在等我完成任務(wù)嗎?\n");
 
    pthread_exit(NULL);
 
}
 
void *thread2()
{
    printf("thread2 : I'm thread 2\n");
    for (i = 0; i < MAX; i++)
        {
            printf("thread2 : number = %d\n",number);
            pthread_mutex_lock(&mut);
            number++;
            pthread_mutex_unlock(&mut);
            sleep(3);
        }
    printf("thread2 :主函數(shù)在等我完成任務(wù)嗎?\n");
    pthread_exit(NULL);
}
 
 
void thread_create(void)
{
    int temp;
    memset(&thread, 0, sizeof(thread)); //comment1
    //創(chuàng)建線程
    if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment2
        printf("線程1創(chuàng)建失敗!\n");
    else
        printf("線程1被創(chuàng)建\n");
    if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
        printf("線程2創(chuàng)建失敗");
    else
        printf("線程2被創(chuàng)建\n");
}
 
void thread_wait(void)
{
    //等待線程結(jié)束
    if(thread[0] !=0) { //comment4
        pthread_join(thread[0],NULL);
        printf("線程1已經(jīng)結(jié)束\n");
    }
    if(thread[1] !=0) { //comment5
        pthread_join(thread[1],NULL);
        printf("線程2已經(jīng)結(jié)束\n");
    }
}
 
int main()
{
    //用默認(rèn)屬性初始化互斥鎖
    pthread_mutex_init(&mut,NULL);
    printf("我是主函數(shù)哦,我正在創(chuàng)建線程,呵呵\n");
    thread_create();
    printf("我是主函數(shù)哦,我正在等待線程完成任務(wù)阿,呵呵\n");
    thread_wait();
    return 0;
}

編譯 :

       gcc -lpthread -o thread_example lp.c

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多