一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

pthread編程基礎(chǔ)

 waston 2016-11-10

1.  pthread線程概念

Linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時(shí)需要使用庫(kù)libpthread.a與vxworks上任務(wù)的概念類似,都是調(diào)度的最小單元,都有共享的堆、棧、代碼區(qū)、全局變量等。

2.  創(chuàng)建線程

int  pthread_create(pthread_t  *  thread,

pthread_attr_t * attr,

void * (*start_routine)(void *),

void * arg)

thread:返回創(chuàng)建的線程的ID

attr:線程屬性,調(diào)度策略、優(yōu)先級(jí)等都在這里設(shè)置,如果為NULL則表示用默認(rèn)屬性

start_routine:線程入口函數(shù),可以返回一個(gè)void*類型的返回值,該返回值可由pthread_join()捕獲

arg:傳給start_routine的參數(shù), 可以為NULL

返回值:成功返回0

3.  設(shè)置線程屬性

線程屬性通過attr進(jìn)行設(shè)置。

設(shè)置與查詢attr結(jié)構(gòu)的為pthread_attr_get***()pthread_attr_set***()兩個(gè)函數(shù)系列。

設(shè)置與查詢線程參數(shù)的為pthread_get***()pthread_set***()兩個(gè)函數(shù)系列。也可以在創(chuàng)建時(shí)通過pthrea_create傳入?yún)?shù)。

注:有些必須在線程創(chuàng)建時(shí)設(shè)置,如調(diào)度策略。

3.1.  調(diào)度策略

調(diào)度策略有三種:

SCHED_OTHER:非實(shí)時(shí)、正常

SCHED_RR:實(shí)時(shí)、輪詢法

SCHED_FIFO:實(shí)時(shí)、先入先出,與vxworks的調(diào)度機(jī)制一致

例程:

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy

3.2.  優(yōu)先級(jí)

線程優(yōu)先級(jí)支持兩種設(shè)置方式,一種是創(chuàng)建時(shí)設(shè)置,另一種是創(chuàng)建后動(dòng)態(tài)設(shè)置

例程:

pthread_attr_setschedparam(&attr, new_priority);

如果是靜態(tài)設(shè)置,則之后會(huì)用該屬性創(chuàng)建任務(wù),如果是動(dòng)態(tài)設(shè)置,則使用下列函數(shù)設(shè)置:

pthread_attr_setschedparam(&attr, &task->prv_priority);

pthread_attr_getschedparam(&attr, &schedparam);

schedparam.sched_priority = new_priority;

pthread_attr_setschedparam(&attr, &schedparam);

pthread_setschedparam(pthrid, sched_policy, &schedparam);

3.3.  脫離同步

Pthread_join()函數(shù)可以使主線程與子線程保持同步。如果設(shè)置了detachstate狀態(tài),則pthread_join()會(huì)失效,線程會(huì)自動(dòng)釋放所占用的資源。線程的缺省狀態(tài)為PHREAD_CREATE_JOINABLE狀態(tài),線程運(yùn)行起來后,一旦被設(shè)置為PTHREAD_CREATE_DETACH狀態(tài),則無法再恢復(fù)到joinable狀態(tài)。

例程:

pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);、

3.4.  調(diào)度繼承

線程A創(chuàng)建了線程B,則線程B的調(diào)度策略是與線程A的調(diào)度策略與線程B的繼承策略有關(guān)的。如果線程B繼承策略為PTHREAD_INHERIT_SCHED,則線程B的調(diào)度策略與線程A相同;如果線程B繼承策略為PTHREAD_EXPLICIT_SCHE,則線程B的調(diào)度策略由attr決定。

pthread_attr_setdetachstate (&attr,PTHREAD_CREATE_DETACHED);

4.  線程取消

4.1.  線程取消定義

Pthread線程可以通過發(fā)送取消請(qǐng)求的方式終止一個(gè)線程的運(yùn)行。

取消線程的操作主要應(yīng)用于下列場(chǎng)景中:有一個(gè)線程在使用select監(jiān)控網(wǎng)口,主控線程此時(shí)接到了用戶的通知,要放棄監(jiān)聽,則主控線程會(huì)向監(jiān)聽線程發(fā)送取消請(qǐng)求。

Linuxpthread線程接收到取消請(qǐng)求時(shí),并不會(huì)立刻終止線程,而是要等到取消點(diǎn)時(shí)才會(huì)結(jié)束任務(wù)。這樣我們可以為取消點(diǎn)建立某些特殊的處理。Select是取消點(diǎn),所以可以退出。

4.2.  取消點(diǎn)

Vxworks可以在任意位置殺死任務(wù),這樣做導(dǎo)致任務(wù)被殺死后的位置不可控,所以vxworks中不會(huì)很少使用taskDeleteHook。

Pthread規(guī)定了取消點(diǎn)的概念。不論線程何時(shí)收到取消請(qǐng)求,都只能在取消點(diǎn)上才能取消線程。這就保證了風(fēng)險(xiǎn)的可控。

Pthread標(biāo)準(zhǔn)指定了以下幾個(gè)取消點(diǎn):

  pthread_testcancel

  所有調(diào)度點(diǎn),如pthread_cond_wait、sigwait、selectsleep

根據(jù)POSIX標(biāo)準(zhǔn),read()、write()等會(huì)引起阻塞的系統(tǒng)調(diào)用都是Cancelation-point,而其他pthread函數(shù)都不會(huì)引起Cancelation動(dòng)作。但是pthread_cancel的手冊(cè)頁(yè)聲稱,由于LinuxThread庫(kù)與C庫(kù)結(jié)合得不好,因而目前C庫(kù)函數(shù)都不是Cancelation-point,因此可以在需要作為Cancelation-point的系統(tǒng)調(diào)用前后調(diào)用pthread_testcancel(),從而達(dá)到POSIX標(biāo)準(zhǔn)所要求的目標(biāo),即如下代碼段:

pthread_testcancel();

retcode = read(fd, buffer, length);

pthread_testcancel();

這段代碼可以保證read附近有取消點(diǎn),但是否有可能會(huì)卡在read中無法返回呢?

如果線程處于無限循環(huán)中,且循環(huán)體內(nèi)沒有執(zhí)行至取消點(diǎn)的必然路徑,則線程無法由外部其他線程的取消請(qǐng)求而終止。因此在這樣的循環(huán)體的必經(jīng)路徑上應(yīng)該加入pthread_testcancel()調(diào)用。

4.3.  線程取消函數(shù)

int pthread_cancel(pthread_t thread)

發(fā)送終止信號(hào)給thread線程,如果成功則返回0,否則為非0值。發(fā)送成功并不意味著thread會(huì)終止。

int pthread_setcancelstate(int state, int *oldstate)

設(shè)置本線程對(duì)Cancel信號(hào)的反應(yīng),state有兩種值:PTHREAD_CANCEL_ENABLE(缺?。┖?span lang="EN-US">PTHREAD_CANCEL_DISABLE,分別表示收到信號(hào)后設(shè)為CANCLED狀態(tài)和忽略CANCEL信號(hào)繼續(xù)運(yùn)行;old_state如果不為NULL則存入原來的Cancel狀態(tài)以便恢復(fù)。

int pthread_setcanceltype(int type, int *oldtype)

設(shè)置本線程取消動(dòng)作的執(zhí)行時(shí)機(jī),type由兩種取值:PTHREAD_CANCEL_DEFFEREDPTHREAD_CANCEL_ASYCHRONOUS,僅當(dāng)Cancel狀態(tài)為Enable時(shí)有效,分別表示收到信號(hào)后繼續(xù)運(yùn)行至下一個(gè)取消點(diǎn)再退出和立即執(zhí)行取消動(dòng)作(退出);oldtype如果不為NULL則存入原來的取消動(dòng)作類型值。

void pthread_testcancel(void)

檢查本線程是否處于Canceld狀態(tài),如果是,則進(jìn)行取消動(dòng)作,否則直接返回。

4.4.  例程

#include

#include

#include

 

pthread_key_t key;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond =   PTHREAD_COND_INITIALIZER;

unsigned long abc=0;

 

void* Test03(void *p)

{

    printf("Cancel point");

    return NULL;

}

 

void* Test01(void* ptr)

{

    pthread_cleanup_push(Test03, NULL); /* push */

    while(1)

    {

        abc++;

        pthread_testcancel();

    }

    pthread_cleanup_pop(0); /* pop */

    return NULL;

}

 

void* Test02(void* ptr)

{

    while(1)

    {

        sleep(2);

        printf("2222cond_wait:abc=0xx\n", abc);

    }

   

    return NULL;

}

 

int main(void)

{

    int tid1, tid2;

    int ret;

 

    printf("Start:\n");

    ret = pthread_create(&tid1, NULL, Test01, NULL);

    ret = pthread_create(&tid2, NULL, Test02, NULL);

 

    sleep(6);

    pthread_cancel(tid1);

    pthread_join(tid1, NULL);

    pthread_join(tid2, NULL);

   

    return 0;

}

 

結(jié)果:

Start:

2222cond_wait:abc=0x22c29a05

2222cond_wait:abc=0x47b49007

Cancel point2222cond_wait:abc=0x6c9de3ad

2222cond_wait:abc=0x6c9de3ad

2222cond_wait:abc=0x6c9de3ad

如果不加取消點(diǎn)pthread_testcancel(),線程1無法退出。

5.  線程終止方式

線程終止有兩種情況(不考慮進(jìn)程),一種是線程主體函數(shù)return時(shí),線程會(huì)自動(dòng)終止,此時(shí)的退出是可預(yù)知的;另一種是其它線程向通以進(jìn)程下的線程發(fā)送取消請(qǐng)求,線程會(huì)根據(jù)情況判斷是否終止,此時(shí)的終止是不可預(yù)知的。

Vxworks中的任務(wù)與此類似。任務(wù)的主體函數(shù)return時(shí),任務(wù)會(huì)自動(dòng)終止;其它任務(wù)調(diào)用taskDelete()可以殺死任意一個(gè)任務(wù)。TaskDelete()并不安全,因?yàn)槿蝿?wù)可能被殺死在任意一個(gè)時(shí)刻。

5.1.  線程終止時(shí)的清理

不論是可預(yù)見的線程終止還是異常終止,都會(huì)存在資源釋放的問題,在不考慮因運(yùn)行出錯(cuò)而退出的前提下,如何保證線程終止時(shí)能順利的釋放掉自己所占用的資源,特別是鎖資源,就是一個(gè)必須考慮解決的問題。

最經(jīng)常出現(xiàn)的情形是資源獨(dú)占鎖的使用:線程為了訪問臨界資源而為其加上鎖,但在訪問過程中被外界取消,如果線程處于響應(yīng)取消狀態(tài),且采用異步方式響應(yīng),或者在打開獨(dú)占鎖以前的運(yùn)行路徑上存在取消點(diǎn),則該臨界資源將永遠(yuǎn)處于鎖定狀態(tài)得不到釋放。外界取消操作是不可預(yù)見的,因此的確需要一個(gè)機(jī)制來簡(jiǎn)化用于資源釋放的編程。

POSIX線程API中提供了一個(gè)pthread_cleanup_push()/pthread_cleanup_pop()函數(shù)對(duì)用于自動(dòng)釋放資源,相當(dāng)于是增加了一個(gè)析構(gòu)函數(shù)。pthread_cleanup_push()的調(diào)用點(diǎn)到pthread_cleanup_pop()之間的程序段中的終止動(dòng)作(包括調(diào)用pthread_exit()和取消點(diǎn)終止)都將執(zhí)行pthread_cleanup_push()所指定的清理函數(shù)。

API定義如下:

void pthread_cleanup_push(void (*routine) (void  *),  void *arg)

void pthread_cleanup_pop(int execute)

pthread_cleanup_push()/pthread_cleanup_pop()

采用先入后出的棧結(jié)構(gòu)管理,void routine(void *arg)函數(shù)在調(diào)用pthread_cleanup_push()時(shí)壓入清理函數(shù)棧,多次對(duì)pthread_cleanup_push()的調(diào)用將在清理函數(shù)棧中形成一個(gè)函數(shù)鏈,在執(zhí)行該函數(shù)鏈時(shí)按照壓棧的相反順序彈出。

execute參數(shù)表示執(zhí)行到pthread_cleanup_pop()時(shí)是否在彈出清理函數(shù)的同時(shí)執(zhí)行該函數(shù),為0表示不執(zhí)行,非0為執(zhí)行;這個(gè)參數(shù)并不影響異常終止時(shí)清理函數(shù)的執(zhí)行。

這兩個(gè)其實(shí)是宏,必須成對(duì)出現(xiàn),否則會(huì)編譯不過。

編譯。在下面的例子里,當(dāng)線程在"do some work"中終止時(shí),將主動(dòng)調(diào)用pthread_mutex_unlock(mut),以完成解鎖動(dòng)作。

pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);

pthread_mutex_lock(&mut);

/* do some work */

pthread_mutex_unlock(&mut);

pthread_cleanup_pop(0);

必須要注意的是,如果線程處于PTHREAD_CANCEL_ASYNCHRONOUS狀態(tài),上述代碼段就有可能出錯(cuò),因?yàn)?/span>CANCEL事件有可能在pthread_cleanup_push()pthread_mutex_lock()之間發(fā)生,或者在pthread_mutex_unlock()pthread_cleanup_pop()之間發(fā)生,從而導(dǎo)致清理函數(shù)unlock一個(gè)并沒有加鎖的mutex變量,造成錯(cuò)誤。因此,在使用清理函數(shù)的時(shí)候,都應(yīng)該暫時(shí)設(shè)置成PTHREAD_CANCEL_DEFERRED模式。為此,pthread中還提供了一對(duì)不保證可移植的pthread_cleanup_push_defer_np()/pthread_cleanup_pop_defer_np()擴(kuò)展函數(shù),功能與以下代碼段相當(dāng):

{

int oldtype;

 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);

 pthread_cleanup_push(routine, arg);

 ...

 pthread_cleanup_pop(execute);

 pthread_setcanceltype(oldtype, NULL);

 }

5.2.  線程終止的同步及其返回值

一般情況下,進(jìn)程中各個(gè)線程的運(yùn)行都是相互獨(dú)立的,線程的終止并不會(huì)通知,也不會(huì)影響其他線程,終止的線程所占用的資源也并不會(huì)隨著線程的終止而得到釋放。正如進(jìn)程之間可以用wait()系統(tǒng)調(diào)用來同步終止并釋放資源一樣,線程之間也有類似機(jī)制,那就是pthread_join()函數(shù)。

void pthread_exit(void *retval)

int pthread_join(pthread_t th, void **thread_return)

int pthread_detach(pthread_t th)

 

pthread_join()的調(diào)用者將掛起并等待th線程終止,retvalpthread_exit()調(diào)用者線程(線程IDth)的返回值,如果thread_return不為NULL,則*thread_return=retval。需要注意的是一個(gè)線程僅允許唯一的一個(gè)線程使用pthread_join()等待它的終止,并且被等待的線程應(yīng)該處于可join狀態(tài),即非DETACHED狀態(tài)。

如果進(jìn)程中的某個(gè)線程執(zhí)行了pthread_detach(th),則th線程將處于DETACHED狀態(tài),這使得th線程在結(jié)束運(yùn)行時(shí)自行釋放所占用的內(nèi)存資源,同時(shí)也無法由pthread_join()同步,pthread_detach()執(zhí)行之后,對(duì)th請(qǐng)求pthread_join()將返回錯(cuò)誤。

一個(gè)可join的線程所占用的內(nèi)存僅當(dāng)有線程對(duì)其執(zhí)行了pthread_join()后才會(huì)釋放,因此為了避免內(nèi)存泄漏,所有線程的終止,要么已設(shè)為DETACHED,要么就需要使用pthread_join()來回收。

5.3.  關(guān)于ptread_exite()return

理論上說,pthread_exit()和線程宿體函數(shù)退出的功能是相同的,函數(shù)結(jié)束時(shí)會(huì)在內(nèi)部自動(dòng)調(diào)用pthread_exit()來清理線程相關(guān)的資源。但實(shí)際上二者由于編譯器的處理有很大的不同。

在進(jìn)程主函數(shù)(main())中調(diào)用pthread_exit(),只會(huì)使主函數(shù)所在的線程(可以說是進(jìn)程的主線程)退出;而如果是return,編譯器將使其調(diào)用進(jìn)程退出的代碼(如_exit()),從而導(dǎo)致進(jìn)程及其所有線程結(jié)束運(yùn)行。

其次,在線程宿主函數(shù)中主動(dòng)調(diào)用return,如果return語(yǔ)句包含在pthread_cleanup_push()/pthread_cleanup_pop()對(duì)中,則不會(huì)引起清理函數(shù)的執(zhí)行,反而會(huì)導(dǎo)致segment fault

5.4.  判斷是否為同一個(gè)線程

int pthread_equal(pthread_t thread1, pthread_t thread2)

判斷兩個(gè)線程描述符是否指向同一線程。在LinuxThreads中,線程ID相同的線程必然是同一個(gè)線程,因此,這個(gè)函數(shù)的實(shí)現(xiàn)僅僅判斷thread1thread2是否相等。

5.5.  僅執(zhí)行一次的操作

int pthread_once(pthread_once_t *once_control, void (*init_routine) (void))

本函數(shù)使用初值為PTHREAD_ONCE_INITonce_control變量保證init_routine()函數(shù)在本進(jìn)程執(zhí)行序列中僅執(zhí)行一次。這個(gè)類似與線程的構(gòu)造函數(shù)。

#include

#include

pthread_once_t  once=PTHREAD_ONCE_INIT;

void    once_run(void)

{

        printf("once_run in thread %d\n",pthread_self());

}

void * child1(void *arg)

{

        int tid=pthread_self();

        printf("thread %d enter\n",tid);

        pthread_once(&once,once_run);

        printf("thread %d returns\n",tid);

}

void * child2(void *arg)

{

        int tid=pthread_self();

        printf("thread %d enter\n",tid);

        pthread_once(&once,once_run);

        printf("thread %d returns\n",tid);

}

int main(void)

{

        int tid1,tid2;

        printf("hello\n");

        pthread_create(&tid1,NULL,child1,NULL);

        pthread_create(&tid2,NULL,child2,NULL);

        sleep(10);

        printf("main thread exit\n");

        return 0;

}

once_run()函數(shù)僅執(zhí)行一次,且究竟在哪個(gè)線程中執(zhí)行是不定的,盡管pthread_once(&once,once_run)出現(xiàn)在兩個(gè)線程中。

LinuxThreads使用互斥鎖和條件變量保證由pthread_once()指定的函數(shù)執(zhí)行且僅執(zhí)行一次,而once_control則表征是否執(zhí)行過。如果once_control的初值不是PTHREAD_ONCE_INITLinuxThreads定義為0),pthread_once()的行為就會(huì)不正常。在LinuxThreads中,實(shí)際"一次性函數(shù)"的執(zhí)行狀態(tài)有三種:NEVER0)、IN_PROGRESS1)、DONE2),如果once初值設(shè)為1,則由于所有pthread_once()都必須等待其中一個(gè)激發(fā)"已執(zhí)行一次"信號(hào),因此所有pthread_once()都會(huì)陷入永久的等待中;如果設(shè)為2,則表示該函數(shù)已執(zhí)行過一次,從而所有pthread_once()都會(huì)立即返回0。

pthread_kill_other_threads_np()

void pthread_kill_other_threads_np(void)

這個(gè)函數(shù)是LinuxThreads針對(duì)本身無法實(shí)現(xiàn)的POSIX約定而做的擴(kuò)展。POSIX要求當(dāng)進(jìn)程的某一個(gè)線程執(zhí)行exec*系統(tǒng)調(diào)用在進(jìn)程空間中加載另一個(gè)程序時(shí),當(dāng)前進(jìn)程的所有線程都應(yīng)終止。由于LinuxThreads的局限性,該機(jī)制無法在exec中實(shí)現(xiàn),因此要求線程執(zhí)行exec前手工終止其他所有線程。pthread_kill_other_threads_np()的作用就是這個(gè)。

需要注意的是,pthread_kill_other_threads_np()并沒有通過pthread_cancel()來終止線程,而是直接向管理線程發(fā)"進(jìn)程退出"信號(hào),使所有其他線程都結(jié)束運(yùn)行,而不經(jīng)過Cancel動(dòng)作,當(dāng)然也不會(huì)執(zhí)行退出回調(diào)函數(shù)。盡管LinuxThreads的實(shí)驗(yàn)結(jié)果與文檔說明相同,但代碼實(shí)現(xiàn)中卻是用的__pthread_sig_cancel信號(hào)來kill線程,應(yīng)該效果與執(zhí)行pthread_cancel()是一樣的,其中原因目前還不清楚。

6.  TSD

6.1.  TSD概念

在單線程程序中,我們經(jīng)常要用到"全局變量"以實(shí)現(xiàn)多個(gè)函數(shù)間共享數(shù)據(jù)。在多線程環(huán)境下,由于數(shù)據(jù)空間是共享的,因此全局變量也為所有線程所共有。但有時(shí)應(yīng)用程序設(shè)計(jì)中有必要提供線程私有的全局變量,僅在某個(gè)線程中有效,但卻可以跨多個(gè)函數(shù)訪問,比如程序可能需要每個(gè)線程維護(hù)一個(gè)鏈表,而使用相同的函數(shù)操作,最簡(jiǎn)單的辦法就是使用同名而不同變量地址的線程相關(guān)數(shù)據(jù)結(jié)構(gòu)。這樣的數(shù)據(jù)結(jié)構(gòu)可以由Posix線程庫(kù)維護(hù),稱為線程私有數(shù)據(jù)(Thread-specific Data,或TSD)。

6.2.  創(chuàng)建與注銷

Posix定義了兩個(gè)API分別用來創(chuàng)建和注銷TSD

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *))
 該函數(shù)從TSD池中分配一項(xiàng),將其值賦給key供以后訪問使用。如果destr_function不為空,在線程退出(pthread_exit())時(shí)將以key所關(guān)聯(lián)的數(shù)據(jù)為參數(shù)調(diào)用destr_function(),以釋放分配的緩沖區(qū)。不論哪個(gè)線程調(diào)用pthread_key_create(),所創(chuàng)建的key都是所有線程可訪問的,但各個(gè)線程可根據(jù)自己的需要往key中填入不同的值,這就相當(dāng)于提供了一個(gè)同名而不同值的全局變量。在LinuxThreads的實(shí)現(xiàn)中,TSD池用一個(gè)結(jié)構(gòu)數(shù)組表示:

static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
創(chuàng)建一個(gè)TSD就相當(dāng)于將結(jié)構(gòu)數(shù)組中的某一項(xiàng)設(shè)置為"in_use",并將其索引返回給*key,然后設(shè)置destructor函數(shù)為destr_function注銷一個(gè)TSD采用如下API

int pthread_key_delete(pthread_key_t key)
這個(gè)函數(shù)并不檢查當(dāng)前是否有線程正使用該TSD,也不會(huì)調(diào)用清理函數(shù)(destr_function),而只是將TSD釋放以供下一次調(diào)用pthread_key_create()使用。在LinuxThreads中,它還會(huì)將與之相關(guān)的線程數(shù)據(jù)項(xiàng)設(shè)為NULL(見"訪問")。 6.3.  訪問TSD的讀寫都通過專門的Posix Thread函數(shù)進(jìn)行,其API定義如下:

int  pthread_setspecific(pthread_key_t  key,  const   void  *pointer)void * pthread_getspecific(pthread_key_t key)
寫入(pthread_setspecific())時(shí),將pointer的值(不是所指的內(nèi)容)與key相關(guān)聯(lián),而相應(yīng)的讀出函數(shù)則將與key相關(guān)聯(lián)的數(shù)據(jù)讀出來。數(shù)據(jù)類型都設(shè)為void *,因此可以指向任何類型的數(shù)據(jù)。LinuxThreads中,使用了一個(gè)位于線程描述結(jié)構(gòu)(_pthread_descr_struct)中的二維void *指針數(shù)組來存放與key關(guān)聯(lián)的數(shù)據(jù),數(shù)組大小由以下幾個(gè)宏來說明:

#define PTHREAD_KEY_2NDLEVEL_SIZE       32#define PTHREAD_KEY_1STLEVEL_SIZE   \((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1)/ PTHREAD_KEY_2NDLEVEL_SIZE)    其中在/usr/include/bits/local_lim.h中定義了PTHREAD_KEYS_MAX1024,    因此一維數(shù)組大小為32。而具體存放的位置由key值經(jīng)過以下計(jì)算得到:idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZEidx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE

也就是說,數(shù)據(jù)存放與一個(gè)32×32的稀疏矩陣中。同樣,訪問的時(shí)候也由key值經(jīng)過類似計(jì)算得到數(shù)據(jù)所在位置索引,再取出其中內(nèi)容返回。

6.4.  使用范例

/* fireaxe的例程 */

#include

#include

pthread_key_t   key;

void echomsg(int t)

{

        printf("destructor excuted in thread %d,param=%d\n",pthread_self(),t);

}

void * child1(void *arg)

{

        int tid=pthread_self();

        printf("thread %d enter\n",tid);

        pthread_setspecific(key,(void *)tid);

        sleep(2);

        printf("thread %d returns %d\n",tid,pthread_getspecific(key));

        sleep(5);

}

void * child2(void *arg)

{

        int tid=pthread_self();

        printf("thread %d enter\n",tid);

        pthread_setspecific(key,(void *)tid);

        sleep(1);

        printf("thread %d returns %d\n",tid,pthread_getspecific(key));

        sleep(5);

}

int main(void)

{

        int tid1,tid2;

        printf("hello\n");

        pthread_key_create(&key,echomsg);

        pthread_create(&tid1,NULL,child1,NULL);

        pthread_create(&tid2,NULL,child2,NULL);

        sleep(10);

        pthread_key_delete(key);

        printf("main thread exit\n");

        return 0;

}

給例程創(chuàng)建兩個(gè)線程分別設(shè)置同一個(gè)線程私有數(shù)據(jù)為自己的線程ID,為了檢驗(yàn)其私有性,程序錯(cuò)開了兩個(gè)線程私有數(shù)據(jù)的寫入和讀出的時(shí)間,從程序運(yùn)行結(jié)果可以看出,兩個(gè)線程對(duì)TSD的修改互不干擾。同時(shí),當(dāng)線程退出時(shí),清理函數(shù)會(huì)自動(dòng)執(zhí)行,參數(shù)為tid。

7.  線程同步

7.1.  互斥鎖(互斥信號(hào)量)

Pthread的互斥鎖與vxworks的互斥信號(hào)量類似,都是用于互斥保護(hù)。

需要注意的是,linux有取消點(diǎn)的概念,即任務(wù)在運(yùn)行時(shí)可以被取消。如果使用了互斥鎖,可能會(huì)造成為解鎖就被取消。為了解決這一問題,linux提供了可以在取消上加回調(diào)函數(shù)的功能:

pthread_cleanup_push()

pthread_cleanup_pop()

兩個(gè)必須成對(duì)出現(xiàn)如果線程運(yùn)行到兩個(gè)函數(shù)之間被取消時(shí),push注冊(cè)的函數(shù)會(huì)被調(diào)用。

例程:

如果沒有pushpop兩行,則tid1被殺死后會(huì)導(dǎo)致tid2無法獲取到互斥鎖。

/* fireaxe的例程 */

#include

#include

#include

 

pthread_key_t key;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond =   PTHREAD_COND_INITIALIZER;

 

void* Test01(void* ptr)

{

    pthread_cleanup_push(pthread_mutex_unlock, &mutex); /* push */

    while(1)

    {

        sleep(3);

        pthread_mutex_lock(&mutex);

        printf("1111mutex_lock\n");

        pthread_cond_wait(&cond, &mutex);

        printf("1111cond_wait\n");

        pthread_mutex_unlock(&mutex);

    }

    pthread_cleanup_pop(0); /* pop */

    return NULL;

}

 

void* Test02(void* ptr)

{

    while(1)

    {

        sleep(2);

        pthread_mutex_lock(&mutex);

        printf("2222mutex_lock\n");

        pthread_cond_wait(&cond, &mutex);

        printf("2222cond_wait\n");

        pthread_mutex_unlock(&mutex);

        sleep(2);

    }

   

    return NULL;

}

 

int main(void)

{

    int tid1, tid2;

    int ret;

 

    pthread_mutex_init(&mutex, NULL);

    pthread_mutex_init(&mutex, NULL);

    printf("Start:\n");

    ret = pthread_create(&tid1, NULL, Test01, NULL);

    ret = pthread_create(&tid2, NULL, Test02, NULL);

    printf("ret = 0x%x\n", ret);

 

    sleep(4);

    pthread_cancel(tid1);

   

    do

    {

        sleep(4);

        pthread_cond_signal(&cond);

    } while(1);

    printf("end.\n");

   

    return 0;

   

}

7.2.  條件變量(同步信號(hào)量)

Pthread的條件變量與vxworks中同步信號(hào)量類似,都是用于任務(wù)同步。區(qū)別是條件變量的操作不是原子操作,需要借助互斥鎖保證其原子性。7.3.  信號(hào)燈(計(jì)數(shù)信號(hào)量)

Pthread的信號(hào)燈與vxworks中計(jì)數(shù)信號(hào)量信號(hào)量類似,都是用于表示資源是否可用。

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产高清在线不卡一区| 色婷婷在线视频免费播放| 风韵人妻丰满熟妇老熟女av| 黄片在线观看一区二区三区| 亚洲精品国产第一区二区多人| 熟女一区二区三区国产| 中文字幕一区二区免费| 成在线人免费视频一区二区| 九九蜜桃视频香蕉视频| 国产一区二区三区香蕉av| 好吊视频一区二区在线| 风间中文字幕亚洲一区| 国产又色又爽又黄的精品视频| 国产剧情欧美日韩中文在线| 亚洲综合精品天堂夜夜| 国产又大又猛又粗又长又爽| 日韩欧美黄色一级视频| 欧美一区二区不卡专区| 东京热电东京热一区二区三区| 免费人妻精品一区二区三区久久久| 久久福利视频这里有精品| 在线免费视频你懂的观看| 在线日韩中文字幕一区 | 欧美午夜不卡在线观看| 欧美精品一区二区水蜜桃| 婷婷基地五月激情五月| 成人国产激情福利久久| 草草夜色精品国产噜噜竹菊| 欧美日韩免费黄片观看| 国产精品免费视频久久| 免费观看日韩一级黄色大片| 国产精品免费视频视频| 久热青青草视频在线观看| 高清一区二区三区四区五区| 色哟哟在线免费一区二区三区| 国产成人国产精品国产三级| 日韩特级黄片免费观看| 中文字幕日韩欧美一区| 年轻女房东2中文字幕| 日韩成人中文字幕在线一区 | 久久亚洲午夜精品毛片|