第7章 ARM Linux多線程開發(fā)實(shí)例(2010-5-13)_第1頁(yè)
第7章 ARM Linux多線程開發(fā)實(shí)例(2010-5-13)_第2頁(yè)
第7章 ARM Linux多線程開發(fā)實(shí)例(2010-5-13)_第3頁(yè)
第7章 ARM Linux多線程開發(fā)實(shí)例(2010-5-13)_第4頁(yè)
第7章 ARM Linux多線程開發(fā)實(shí)例(2010-5-13)_第5頁(yè)
已閱讀5頁(yè),還剩96頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第7章ARMLinux多線程開發(fā)實(shí)例

7.1

Linux多線程相關(guān)API

7.2信號(hào)燈

7.3互斥量

7.4條件變量

番禺職業(yè)技術(shù)學(xué)院番禺職業(yè)技術(shù)學(xué)院

7.1

Linux多線程相關(guān)API

Linux有多線程開發(fā)的Pthread

庫(kù)支持。最基本概念:線程、互斥鎖、條件。①線程操作又分線程的創(chuàng)建、退出、等待。②互斥鎖則包括4種操作:創(chuàng)建、銷毀、加鎖和解鎖。③條件操作有5種操作:創(chuàng)建、銷毀、觸發(fā)、廣播和等待。其他的一些線程擴(kuò)展概念,如信號(hào)燈等,都可以通過上面的三個(gè)基本元素的基本操作封裝出來。表7.1.線程函數(shù)列表7.1.1線程的創(chuàng)建1.pthread_create函數(shù)pthread_create用于創(chuàng)建一個(gè)新的線程。其函數(shù)原型為:#include

<pthread.h>int

pthread_create(pthread_t

*restrict

tidp,const

pthread_attr_t

*restrict

attr,

void

*(*start_rtn)(void),void

*restrict

arg);返回值:若是成功建立線程返回0,否則返回錯(cuò)誤的編號(hào)。函數(shù)說明:第1個(gè)參數(shù)為指向要?jiǎng)?chuàng)建的線程的線程id指針,第2個(gè)參數(shù)用來設(shè)置線程屬性,第3個(gè)參數(shù)是線程運(yùn)行函數(shù)的起始地址,最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)。這里,函數(shù)thread不需要參數(shù),所以最后一個(gè)參數(shù)設(shè)為空指針。第2個(gè)參數(shù)也設(shè)為空指針,這樣將生成默認(rèn)屬性的線程。當(dāng)創(chuàng)建線程成功,函數(shù)返回0,否則失敗,常見的錯(cuò)誤返回代碼為EAGAIN和EINVAL。EAGAIN表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過多了;EINVAL表示第2個(gè)參數(shù)代表的線程屬性值非法。創(chuàng)建線程成功后,新創(chuàng)建的線程則運(yùn)行參數(shù)三和參數(shù)四確定的函數(shù),原來的線程則繼續(xù)運(yùn)行下一行代碼。

例7.1線程的創(chuàng)建(gettid.c)#include<pthread.h>voidprintids(constchar*s){printf(“%s

pid:%u

tid:%u\n“,getpid(),pthread_self());}void*thr_fn(void*arg){printf(“newthread:“);}

intmain(){interr;pthread_t

tid;err=pthread_create(&tid,NULL,thr_fn,NULL);if(err!=0)

printf(“can’tcreatethread:%s\n”,strerror(err));printids(“mainthread:”);sleep(1);exit(0);}

進(jìn)程的編譯需要要加上參數(shù)–lpthread,否則提示找不到函數(shù)的錯(cuò)誤。具體編譯方法是:gcc–lpthread–ogettid

gettid.c運(yùn)行結(jié)果為mainthread:pid14954tid134529024newthread:pid14954tid1345300487.1.2線程的終止1.pthread_join

函數(shù)pthread_join

函數(shù)用來等待一個(gè)線程的結(jié)束。其函數(shù)原型為:#include<pthread.h>int

pthread_join(pthread_t

thread,void**rval_ptr);返回值:若函數(shù)調(diào)用成功返回0,否則返回錯(cuò)誤編號(hào)。第1個(gè)參數(shù)為被等待的線程標(biāo)識(shí)符,第2個(gè)參數(shù)為一個(gè)用戶定義的指針,它可以用來存儲(chǔ)被等待線程的返回值。這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回。

2.pthread_exit

函數(shù)

線程是依進(jìn)程而存在的,當(dāng)進(jìn)程終止時(shí),線程也就終止了。當(dāng)然也有在不終止整個(gè)進(jìn)程的情況下停止它的控制流。(1)線程只是從啟動(dòng)例程中返回,返回值是線程的退出碼。(2)線程可以被同一進(jìn)程中的其他線程取消。(3)線程調(diào)用pthread_exit.

pthread_exit

:是一個(gè)線程的結(jié)束。兩種途徑:當(dāng)函數(shù)結(jié)束了,調(diào)用它的線程也就結(jié)束了;另一種方式是通過函數(shù)pthread_exit

來實(shí)現(xiàn)。其函數(shù)原型為:

voidpthread_exit(void*__retval)

唯一的參數(shù)是函數(shù)的返回代碼,只要pthread_join

中的第二個(gè)參數(shù)thread_return

不是NULL,這個(gè)值將被傳遞給thread_return。需要說明的是,一個(gè)線程不能被多個(gè)線程等待,否則第一個(gè)接收到信號(hào)的線程成功返回,其余調(diào)用pthread_join

的線程則返回錯(cuò)誤代碼ESRCH。

例7.2線程終止#include<pthread.h>#include<string.h>void*thr_fn1(void*arg){printf(“thread1returning\n”);return((void*)1);}void*thr_fn2(void*arg){printf(“thread2exiting\n”);return((void*)2);}intmain(){pthread_ttid1,tid2;void*tret;pthread_create(&tid1,NULL,thr_fn1,NULL);pthread_create(&tid2,NULL,thr_fn2,NULL);pthread_join(tid1,&tret);

printf(“thread1exitcode%d\n”,(int)tret);pthread_join(tid2,&tret);

printf(“thread2exitcode%d\n”,(int)tret);exit(0);}運(yùn)行結(jié)果是:thread1returningthread2exitingthread1exitcode1thread2exitcode23.pthread_detach函數(shù)pthread_detach函數(shù)是用于使線程進(jìn)入分離狀態(tài)。其函數(shù)原型為:#include<pthread.h>int

pthread_detach(pthread_t

tid);返回值:若函數(shù)調(diào)用成功返回0,否則返回錯(cuò)誤編號(hào)。在默認(rèn)情況下,線程的終止?fàn)顟B(tài)會(huì)保存到對(duì)該線程調(diào)用pthread_join,如果線程已經(jīng)處于分離狀態(tài),線程的底層存儲(chǔ)資源可以在線程終止時(shí)立即被收回。當(dāng)線程被分離時(shí),并不能用pthread_join函數(shù)等待它的終止?fàn)顟B(tài)。對(duì)分離狀態(tài)的線程進(jìn)行pthread_join的調(diào)用會(huì)產(chǎn)生失敗,返回EINVAL。

4.pthread_cancel函數(shù)

pthread_cancel函數(shù)是用于取消同一進(jìn)程中的其他線程。其函數(shù)原型為:#include<pthread.h>int

pthread_cancel(pthread_t

tid);返回值:若函數(shù)調(diào)用成功返回0,否則返回錯(cuò)誤編號(hào)。在默認(rèn)的情況下,pthread_cancel函數(shù)會(huì)使由tid標(biāo)識(shí)的線程的行為表現(xiàn)為如同調(diào)用了參數(shù)為PTHEAD_CANCELED的pthread_exit函數(shù),但是,線程可以選擇忽略取消方式和控制取消方式。pthread_cancel并不等待線程終止,它僅僅提出請(qǐng)求。5.pthread_cancel_push/pthread_cancel_push_pop函數(shù)pthread_cancel_push/pthread_cancel_pop是線程清理處理程序。其函數(shù)原型為:#include<pthread.h>voidpthread_cancel_push(void(*rtn)(void*),void*arg);voidpthread_cancel_pop(intexecute);參數(shù):rtn為處理程序入口地址,arg為傳遞給處理函數(shù)的參數(shù)。線程可以安排它退出時(shí)需要調(diào)用的函數(shù),這樣的函數(shù)稱為線程清理處理程序,線程可以建立多個(gè)清理處理程序。處理程序記錄在棧中,也就是說它們的執(zhí)行順序與它們注冊(cè)時(shí)的順序相反。注意:如果線程是通過從他的啟動(dòng)例程中返回而終止的,它的處理程序就不會(huì)調(diào)用。還要注意清理處理程序是按照與它們安裝時(shí)相反的順序調(diào)用的。例7.3線程的取消#include<pthread.h>#include<stdio.h>voidcleanup(void*arg){printf(“cleanup:%s\n”,(char*)arg);}void*thr_fn(void*arg)/*線程入口地址*/{printf(“threadstart\n”);pthread_cleanup_push(cleanup,”threadfirsthandler”);/*設(shè)置第一個(gè)線程處理程序*/pthread_cleanup_push(cleanup,”thread

secondhandler”);/*設(shè)置第二個(gè)線程處理程序*/printf(“threadpushcomplete\n”);pthread_cleanup_pop(0);/*取消第一個(gè)線程處理程序*/pthread_cleanup_pop(0);/*取消第二個(gè)線程處理程序*/}intmain(){pthread_t

tid;void*tret;

pthread_creat(&tid,NULL,thr_fn,(void*)1);/*創(chuàng)建一個(gè)線程*/

pthread_join(tid,&tret);/*獲得線程終止?fàn)顟B(tài)*/

ptinrf(“threadexitcode%d\n”,(int)tret);}7.1.3線程的標(biāo)識(shí)每個(gè)進(jìn)程有一個(gè)進(jìn)程ID,每個(gè)線程也有一個(gè)線程ID,進(jìn)程ID在整個(gè)系統(tǒng)中是唯一的,但線程不同,線程ID只在它所屬的進(jìn)程環(huán)境中有效。線程ID用pthread_t數(shù)據(jù)類型來表示,實(shí)現(xiàn)的時(shí)候可以用一個(gè)結(jié)構(gòu)來代表pthread_t數(shù)據(jù)類型,所以可以移植的操作系統(tǒng)不能把它作為整數(shù)處理。1.pthread_self函數(shù)函數(shù)用于獲取自身線程的id。其函數(shù)原型為:#include<pthread.h>pthread_t

pthread_self(void);返回值:調(diào)用線程的線程id。2.pthread_equal函數(shù)pthread_equal函數(shù)用于測(cè)試兩個(gè)線程號(hào)ID是否相同。其函數(shù)原型為:#include<pthread.h>int

pthread_equal(pthread_ttid1,pthread_ttid2);返回值:測(cè)試兩個(gè)線程號(hào)ID是否相同。若相等返回非0值,否則返回0。函數(shù)說明:函數(shù)中的參數(shù)tid1為線程1的ID,tid2為線程2的ID。7.1.4線程的一次性初始化在傳統(tǒng)的順序編程中,一次性初始化經(jīng)常通過使用布爾變量來管理??刂谱兞勘混o態(tài)初始化為0,而任何依賴于初始化的代碼都能測(cè)試該變量。如果變量值仍然為0,則它能實(shí)行初始化,然后將變量置為1。以后檢查的代碼將跳過初始化。在多線程程序設(shè)計(jì)中,如果多個(gè)線程并發(fā)地執(zhí)行初始化序列代碼,2個(gè)線程可能發(fā)現(xiàn)控制變量為0,并且都實(shí)行初始話,而該過程本該僅僅執(zhí)行一次。初始化的狀態(tài)必須由互斥量保護(hù)。如果需要對(duì)一個(gè)posix變量靜態(tài)的初始化,可使用的方法是用一個(gè)互斥量對(duì)該變量的初始話進(jìn)行控制。pthread_once函數(shù)可以對(duì)該變量進(jìn)行動(dòng)態(tài)初始化。7.1.4線程的一次性初始化如果需要對(duì)一個(gè)posix變量靜態(tài)的初始化,可使用的方法是用一個(gè)互斥量對(duì)該變量的初始化進(jìn)行控制。pthread_once函數(shù)可以對(duì)該變量進(jìn)行動(dòng)態(tài)初始化。其函數(shù)原理如下:#include<pthread.h>pthread_once_t

once_control=PTHREAD_ONCE_INIT;int

pthread_once(pthread_once_t*once_control,void(*init_routine)(void));、函數(shù)參數(shù):參數(shù)once_control為控制變量,init_routine為初始化函數(shù)。返回值:若函數(shù)調(diào)用成功返回0,否則返回錯(cuò)誤編號(hào)。函數(shù)說明:類型為pthread_once_t的變量是一個(gè)控制變量??刂谱兞勘仨毷褂肞THREAD_ONCE_INIT宏靜態(tài)地初始化。例7.4pthread_once函數(shù)的應(yīng)用(once.c)#include<pthread.h>pthread_once_tonce=PTHREAD_ONCE_INIT;pthread_mutex_t

mutex;/*互斥量*/voidonce_init_routine(void)

/*一次初始化函數(shù)*/{intstatus;status=pthread_mutex_init(&mutex,NULL);/*初始化互斥量*/

If(status==0)

printf(“Init

success!,Myidis%u”,pthread_self());}void*child_thread(void*arg){printf(“I’mchild,Myidis%u”,pthread_self());

pthread_once(&once,once_init_routine);/*子線程調(diào)用一次性初始化函數(shù)*/}int

main(int

argc,char*argv[]){pthread_t

child_thread_id;pthread_create(&child_thread_id,NULL,child_thread,NULL);/*創(chuàng)建子線程*/

printf(“I’m

father,myidis%u”,pthread_self());

pthread_once(&once_block,once_init_routine);/*父線程調(diào)用一次性初始化函數(shù)*/

pthread_join(child_thread_id,NULL);}程序運(yùn)行結(jié)果如下:./onceI’mfather,Myidis3086874304Initsuccess!,Myidis3086874304I’mchild,Myidis3086871472 從上面的結(jié)果可以看到當(dāng)主函數(shù)初始化成功后,子函數(shù)初始化失敗。7.1.5線程的私有數(shù)據(jù)在進(jìn)程內(nèi)的所有線程共享相同的地址空間,任何聲明為靜態(tài)或外部的變量,或在進(jìn)程堆聲明的變量,都可以被進(jìn)程所有的線程讀寫。但有時(shí)在應(yīng)用程序設(shè)計(jì)過程中有必要提供線程私有的全局變量,僅在線程中有效,卻可跨多個(gè)函數(shù)進(jìn)行訪問,如程序可能需要每個(gè)線程維護(hù)一個(gè)鏈表,要使用相同的函數(shù)操作,最簡(jiǎn)單的辦法就是使用同名而不同變量地址的線程相關(guān)數(shù)據(jù)結(jié)構(gòu)。這樣的數(shù)據(jù)結(jié)構(gòu)可以由POSIX線程庫(kù)維護(hù),稱為線程私有數(shù)據(jù)(Thread-SpecificData,TSD)。7.1.5線程的私有數(shù)據(jù)POSIX線程庫(kù)提供了函數(shù)pthread_key_create來創(chuàng)建線程鍵。其函數(shù)原型為:#include<pthread.h>int

pthread_key_create(pthread_key*key,void(*destructor)(void*));函數(shù)參數(shù):參數(shù)key為私有數(shù)據(jù)鍵,destructor為清理函數(shù)。返回值:若函數(shù)調(diào)用成功返回0,否則返回錯(cuò)誤編號(hào)。函數(shù)說明:函數(shù)用于建立線程私有數(shù)據(jù)鍵。函數(shù)的第1個(gè)參數(shù)為指向一個(gè)鍵值的指針,第2個(gè)參數(shù)指明了一個(gè)destructor函數(shù)(清理函數(shù)),如果這個(gè)參數(shù)不為空,那么當(dāng)每個(gè)線程結(jié)束時(shí),系統(tǒng)將調(diào)用這個(gè)函數(shù)來釋放綁定在這個(gè)鍵上的內(nèi)存塊。這個(gè)函數(shù)常和函數(shù)pthread_once一起使用,為了讓這個(gè)鍵只被創(chuàng)建一次。函數(shù)pthread_once聲明一個(gè)初始化函數(shù),第一次調(diào)用pthread_once時(shí)它執(zhí)行這個(gè)函數(shù),以后的調(diào)用將被它忽略。

例7.5pthread_key_create函數(shù)的應(yīng)用#include<pthread.h>pthread_key_t

tsd_key;pthread_once_t

key_once=PTHREAD_ONCE_INIT;voidonce_routine(void){intstatus;status=pthread_key_create(&tsd_key,NULL);/*初始化線程私有數(shù)據(jù)鍵*/if(status=0)printf(“Keycreatesuccess!Myidis%u\n”,pthread_self());}void*child_thread(void*arg){printf(“I’m

child,Myidis%u\n”,pthread_self());

pthread_once(&key_once,once_routine);/*調(diào)用一次性初始化函數(shù)*/}int

main(int

argc,char*argv[]){pthread_t

child_thread_id;pthread_create(&child_thread_id,NULL,child_thread,NULL);printf(“I’m

father,myidis%u\n”,pthread_self());pthread_once(&key_once,once_routine);}程序運(yùn)行結(jié)果如下:I’mfather,Myidis3086231232Keycreatesuccess!Myidis3086231232I’mchild,Myidis20862284007.2信號(hào)燈7.2.1

POSIX有名信號(hào)燈的API函數(shù)有名信號(hào)燈總是既可用于線程間的同步,又可以用于進(jìn)程間的同步。1.sem_open函數(shù)sem_open函數(shù)用于創(chuàng)建一個(gè)新的有名信號(hào)燈或打開一個(gè)已存在的有名信號(hào)燈。函數(shù)原型如下:#include<semaphore.h>sem_t*sem_open(constchar*name,int

oflag,/*mode_t

mode,unsigned

intvalue*/);函數(shù)參數(shù):參數(shù)name是信號(hào)燈外部名字,oflag為選擇創(chuàng)建或打開一個(gè)現(xiàn)有的信號(hào)燈,mode是權(quán)限位,value是信號(hào)燈初值。返回值:若函數(shù)調(diào)用成功時(shí)返回指向信號(hào)燈的指針,出錯(cuò)時(shí)為SEM_FAILED。函數(shù)說明:oflag參數(shù)可以是0、O_CREAT(創(chuàng)建一個(gè)信號(hào)燈)或O_CREAT|O_EXCL(如果沒有指定的信號(hào)燈就創(chuàng)建),如果指定了O_CREAT,那么第3個(gè)和第4個(gè)參數(shù)是需要的;其中mode參數(shù)指定權(quán)限位,value參數(shù)指定信號(hào)燈的初始值,通常用來指定共享資源的頁(yè)面。該初始不能超過SEM_VALUE_MAX,這個(gè)常值必須低于為32767。二值信號(hào)燈的初始值通常為1,計(jì)數(shù)信號(hào)燈的初始值則往往大于1。

如果指定了O_CREAT(而沒有指定O_EXCL),那么只有所需的信號(hào)燈尚未存在時(shí)才初始化它。所需信號(hào)燈已存在條件下指定O_CREAT不是一個(gè)錯(cuò)誤。該標(biāo)志的意思僅僅是“如果所需信號(hào)燈尚未存在,那就創(chuàng)建并初始化它”。但是所需信號(hào)燈等已存在條件下指定O_CREAT|O_EXCL卻是一個(gè)錯(cuò)誤。

sem_open返回指向sem_t信號(hào)燈的指針,該結(jié)構(gòu)里記錄著當(dāng)前共享資源的數(shù)目。2.sem_close函數(shù)用于關(guān)閉有名信號(hào)燈。函數(shù)原型如下:#include<semaphore.h>int

sem_close(sem_t*sem);函數(shù)參數(shù):參數(shù)sem是指向信號(hào)燈的指針。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:一個(gè)進(jìn)程終止時(shí),內(nèi)核還對(duì)其上仍然打開著的所有有名信號(hào)燈自動(dòng)執(zhí)行這樣的信號(hào)燈關(guān)閉操作。不論該進(jìn)程是自愿終止的還是非自愿終止的,這種自動(dòng)關(guān)閉都會(huì)發(fā)生。

但應(yīng)注意的是關(guān)閉一個(gè)信號(hào)燈并沒有將它從系統(tǒng)中刪除。即Posix有名信號(hào)燈至少是隨內(nèi)核持續(xù)的:即使當(dāng)前沒有進(jìn)程打開著某個(gè)信號(hào)燈,它的值仍然保持。

3.sem_unlink函數(shù)sem_unlink函數(shù)用于在所有進(jìn)程關(guān)閉了命名信號(hào)量之后,將信號(hào)量從系統(tǒng)中刪除。函數(shù)原型如下:#include<semaphore.h>int

sem_unlink(countchar*name);函數(shù)參數(shù):參數(shù)name是信號(hào)燈的外部名字。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:有名信號(hào)燈使用sem_unlink從系統(tǒng)中刪除。每個(gè)信號(hào)燈有一個(gè)引用計(jì)數(shù)器記錄當(dāng)前的打開次數(shù),sem_unlink必須等待這個(gè)數(shù)為0時(shí)才能把name所指的信號(hào)燈從文件系統(tǒng)中刪除。也就是要等待最后一個(gè)sem_close發(fā)生。

4.sem_getvalue函數(shù)函數(shù)sem_getvalue用于測(cè)試信號(hào)燈。函數(shù)原型如下:#include<semaphore.h>int

sem_getvalue(sem_t*sem,int*valp);函數(shù)參數(shù):參數(shù)sem是指向信號(hào)燈的指針。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:sem_getvalue在由valp指向的正數(shù)中返回所指定信號(hào)燈的當(dāng)前值。如果該信號(hào)燈當(dāng)前已上鎖,那么返回值或?yàn)?,或?yàn)槟硞€(gè)負(fù)數(shù),其絕對(duì)值就是等待該信號(hào)燈解鎖的線程數(shù)。5.sem_wait/sem_trywait函數(shù)函數(shù)用于等待共享資源。函數(shù)原型如下:#include<semaphore.h>int

sem_wait(sem_t*sem);int

sem_trywait(sem_t*sem);函數(shù)參數(shù):參數(shù)sem是指向信號(hào)燈的指針。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:可以用sem_wait來申請(qǐng)共享資源,sem_wait函數(shù)可以測(cè)試所指定信號(hào)燈的值,如果該值大于0,那就將它減1并立即返回??梢允褂蒙暾?qǐng)來的共享資源。如果該值等于0,調(diào)用線程就被進(jìn)入睡眠狀態(tài),直到該值變?yōu)榇笥?,這時(shí)再將它減1,函數(shù)隨后返回。sem_wait操作必須是原子的。sem_wait和sem_trywait的差別是:當(dāng)所指定信號(hào)燈的值已經(jīng)是0時(shí),后者并不將調(diào)用線程投入睡眠。相反,它返回一個(gè)EAGAIN錯(cuò)誤。6.sem_post函數(shù)函數(shù)sem_post(sem_t*sem)用來增加信號(hào)量的值。當(dāng)有線程阻塞在這個(gè)信號(hào)量上時(shí),調(diào)用這個(gè)函數(shù)會(huì)使其中的一個(gè)線程不在阻塞,函數(shù)原型如下:#include<semaphore.h>int

sem_post(sem_t*sem);int

sem_getvalue(sem_t*sem,int*valp);函數(shù)參數(shù):參數(shù)sem是指向信號(hào)燈的指針。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:當(dāng)一個(gè)線程使用完某個(gè)信號(hào)燈時(shí),它應(yīng)該調(diào)用sem_post來告訴系統(tǒng)申請(qǐng)的資源已經(jīng)用完。本函數(shù)和sem_wait函數(shù)功能正好相反,它把所指定的信號(hào)燈的值加1,然后喚醒正在等待該信號(hào)燈值變?yōu)檎龜?shù)的任意線程。posix有名信號(hào)燈使用時(shí)應(yīng)注意以下幾點(diǎn):(1)Posix有名信號(hào)燈的值是隨內(nèi)核持續(xù)的。也就是說,一個(gè)進(jìn)程創(chuàng)建了一個(gè)信號(hào)燈,這個(gè)進(jìn)程結(jié)束后,這個(gè)信號(hào)燈還存在,并且信號(hào)燈的值也不會(huì)改變。(2)當(dāng)持有某個(gè)信號(hào)燈鎖的進(jìn)程沒有釋放它就終止時(shí),內(nèi)核并不給該信號(hào)燈解鎖。例7.6posix有名信號(hào)燈應(yīng)用于多線程(7-6.c)#include<semaphore.h>#include<unistd.h>#include<stdio.h>#include<fcntl.h>#include<thread.h>void*thread_function(void*arg);/*線程入口函數(shù)*/voidprint(pid_t);/*共享資源函數(shù)*/sem_t*sem;/*定義Posix有名信號(hào)燈*/int

val;/*定義信號(hào)燈當(dāng)前值*/int

main(int

argc,char*argv[]){intn=0;if(argc!=2){printf(“pleaseinputafilename!\n”);exit(1);}sem=sem_open(argv[1],O_CREAT,0644,3);/*打開一個(gè)信號(hào)燈*/while(n++<5)/*循環(huán)創(chuàng)建5個(gè)子線程,使它們同步運(yùn)行*/{if((pthread_create(&a_thread,NULL,

thread_function,NULL))!=0)

{perror(“Threadcreationfailed”);exit(1);}}pthread_join(a_thread,NULL);sem_close(bin_sem);sem_unlink(argv[1]);}void*thread_function(void*arg){sem_wait(sem);/*申請(qǐng)信號(hào)燈*/print();/*調(diào)用共享代碼段*/sleep(1);

sem_post(sem);/*釋放信號(hào)燈*/

printf(“I’m

finished,my

tidis%d\n”,pthread_self());}voidprint(){printf(“Igetit,my

tidis%d\n”,pthread_self());sem_getvalue(sem,&val);printf(“Nowthevaluehave%d\n”,val);}

程序用循環(huán)的方法建立5個(gè)線程,然后讓它們調(diào)用同一個(gè)線程處理函數(shù)thread_function,在函數(shù)里利用信號(hào)量來限制訪問共享資源的線程數(shù)。共享資源用print函數(shù)來代表,在真正編程中它有可以是一個(gè)終端設(shè)備(如打印機(jī))或是一段有實(shí)際意義的代碼。運(yùn)行結(jié)果為:#gcc–lpthread–o7_6.c#./7_6testIgetit,my

tidis1082330304Nowthevaluehave2Igetit,my

pidis1894Nowthevaluehave1Igetit,my

pidis1895Nowthevaluehave0I’mfinished,my

pidis1893I’mfinished,my

pidis1894I’mfinished,my

pidis1895Igetit,my

pidis1896Nowthevaluehave2Igetit,mypidis1897Nowthevaluehave1I’mfinished,my

pidis1896I’mfinished,my

pidis1897例7.7posix有名信號(hào)燈應(yīng)用于多進(jìn)程(7-7.c)下面是應(yīng)用Posix有名信號(hào)燈的一個(gè)小程序。用它來限制訪問共享代碼的進(jìn)程數(shù)目。#include<semaphore.h>#include<unistd.h>#include<stdio.h>#include<fcntl.h>voidprint(pid_t);sem_t*sem;/*定義Posix有名信號(hào)燈*/int

val;/*定義信號(hào)燈當(dāng)前值*/int

main(int

argc,char*argv[]){intn=0;if(argc!=2){printf(“pleaseinputafilename!\n”);exit(1);}sem=sem_open(argv[1],O_CREAT,0644,2);/*打開一個(gè)信號(hào)燈,初值設(shè)為2*/while(n++<5)/*循環(huán)創(chuàng)建5個(gè)子進(jìn)程,使它們同步運(yùn)行*/{if(fork()==0){sem_wait(sem);/*申請(qǐng)信號(hào)燈*/

print(getpid());/*調(diào)用共享代碼段*/sleep(1);

sem_post(sem);/*釋放信號(hào)燈*/

printf(“I’m

finished,my

pidis%d\n”,getpid());

return0;}wait();/*等待所有子進(jìn)程結(jié)束*/sem_close(sem);sem_unlink(argv[1]);exit(0);}voidprint(pid_t

pid){printf(“Igetit,my

pidis%d\n”,pid);

sem_getvalue(sem,&val);

printf(“Nowthevaluehave%d\n”,val);}程序編譯后運(yùn)行會(huì)得到如下結(jié)果:#./7_7testIgetit,my

tidis1082330304Nowthevaluehave1Igetit,my

tidis1090718784Nowthevaluehave0Ifinished,my

pidis1082330304Ifinished,my

pidis1090718784Igetit,my

tidis1099107264Nowthevaluehave1Igetit,my

tidis1116841120Nowthevaluehave0Ifinished,my

pidis1099107264Ifinished,my

pidis1116841120Igetit,my

tidis1125329600Nowthevaluehave1Ifinished,my

pidis1125329600

7.2.2

POSIX基于內(nèi)存的信號(hào)燈的API函數(shù)1.sem_init/sem_destroy/sem_getvalue

函數(shù)

函數(shù)sem_init/sem_destroy/sem_getvalue用于初始化/關(guān)閉信號(hào)/獲取信號(hào)燈的值等。函數(shù)原型如下:#include<semaphore.h>int

sem_init(sem_t*sem,int

shared,unsigned

intvalue);int

sem_getvalue(sem_t*sem);/*獲取信號(hào)燈的值*/函數(shù)參數(shù):參數(shù)sem為指向信號(hào)燈的指針,shared是作用范圍,value是信號(hào)燈初始值。返回值:若函數(shù)調(diào)用成功則返回0,否則返回-1。函數(shù)說明:基于內(nèi)存的信號(hào)燈是由sem_init初始化的。sem參數(shù)指向必須由應(yīng)用程序分配的sem_t變量。如果shared為0,那么待初始化的信號(hào)燈是在同一進(jìn)程的各個(gè)線程共享的,否則該信號(hào)燈是在進(jìn)程間共享的。當(dāng)shared為零時(shí),該信號(hào)燈必須存放在即將使用它的所有進(jìn)程都能訪問的某種類型的共享內(nèi)存中。跟sem_open一樣,value參數(shù)是該信號(hào)燈的初始值。使用完一個(gè)基于內(nèi)存的信號(hào)燈后,可調(diào)用sem_destroy關(guān)閉它。除了sem_open和sem_close外,其它的poisx有名信號(hào)燈函數(shù)都可以用于基于內(nèi)存的信號(hào)燈。注意:posix基于內(nèi)存的信號(hào)燈和posix有名信號(hào)燈的區(qū)別,區(qū)別如下。(1)sem_open不需類型與shared的參數(shù),有名信號(hào)燈總是可在不同進(jìn)程間共享的。(2)sem_init不使用任何類似于O_CREAT標(biāo)志的東西,也就是說,sem_init總是初始化信號(hào)燈的值。因此,對(duì)于一個(gè)給定的信號(hào)燈,必須小心保證只調(diào)用一次sem_init。(3)sem_open返回一個(gè)指向某個(gè)sem_t變量的指針,該變量由函數(shù)本身分配并初始化。但sem_init的第一個(gè)參數(shù)是一個(gè)指向某個(gè)sem_t變量的指針,該變量由調(diào)用者分配,然后由sem_init函數(shù)初始化。(4)posix有名信號(hào)燈是通過內(nèi)核持續(xù)的,一個(gè)進(jìn)程創(chuàng)建一個(gè)信號(hào)燈,另外的進(jìn)程可以通過該信號(hào)燈的外部名(創(chuàng)建信號(hào)燈使用的文件名)來訪問它。例7.8下面是posix基于內(nèi)存的信號(hào)燈實(shí)現(xiàn)一個(gè)進(jìn)程的各個(gè)線程間的互次。#include<semaphore.h>#include<unistd.h>#include<stdio.h>#include<fcntl.h>#include<pthread.h>#incude<stdlib.h>void*thread_function(void*arg);/*線程入口函數(shù)*/voidprint(void);/*共享資源*/sem_t

bin_sem;/*定義信號(hào)燈*/intvalue;/*定義信號(hào)量的

intmain(){intn=0;pthread_t

a_thread;if((sem_init(&bin_sem,0,2))!=0)/*初始化信號(hào)燈,初始值為2*/{perror(“sem_init”);exit(1);}while(n++<5)/*循環(huán)創(chuàng)建5個(gè)線程*/{if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0){perror(“Threadcreationfailed”);exit(1);}}pthread_join(a_thread,NULL);/*等待子線程返回*/}void*thread_function(void*arg){sem_wait(&bin_sem);/*等待信號(hào)燈*/print();sleep(1);sem_post(&bin_sem);/*掛出信號(hào)燈*/printf(“I

finished,my

pidis%d\n”,pthread_self());pthread_exit(arg);}voidprint(){printf(“Igetit,my

tidis%d\n”,pthread_self());sem_getvalue(&bin_sem,&value);/*獲取信號(hào)燈的值*/printf(“Nowthevaluehave%d\n”,value);}下面是運(yùn)行結(jié)果:#gcc–lpthread–oseminitthread

seminitthread.c#./seminitthread

Igetit,my

tidis1082330304Nowthevaluehave1Igetit,my

tidis1090718784Nowthevaluehave0Ifinished,my

pidis1082330304Ifinished,my

pidis1090718784Igetit,my

tidis1099107264Nowthevaluehave1Igetit,my

tidis1116841120Nowthevaluehave0Ifinished,my

pidis1099107264Ifinished,my

pidis1116841120Igetit,my

tidis1125329600Nowthevaluehave1Ifinished,my

pidis1125329600//下面是用exit()函數(shù)結(jié)束進(jìn)程的程序代碼:#include<stdlib.h>#include<stdio.h>int

main(void){printf("Usingexit...\n");

printf("Thisisthecontentinbuffer");

exit(0);}輸出信息:Usingexit...Thisisthecontentinbuffer7.3互斥量1.mutex線程訪問控制(1)初始化互斥量用pthread_mutex_t數(shù)據(jù)類型來表示,在使用互斥量之前,必須首先對(duì)它進(jìn)行初始化,可以把它置為常量PTHREAD_MUTEX_INITIALIZER(只對(duì)靜態(tài)分配的互斥量),也可以通過調(diào)用pthread_mutex_init函數(shù)進(jìn)行初始化,如果動(dòng)態(tài)地分配互斥量,那么釋放內(nèi)存前需要調(diào)用pthread_mutex_destroy。下面介紹常用的互斥量函數(shù)。pthread_mutex_init函數(shù)用于初始化互斥鎖。用于初始化互斥鎖。其函數(shù)#include<pthread.h>int

pthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutex_t*attr);//初始化互斥鎖int

pthread_mutex_destroy(pthread_mutex_t*mutex);//銷毀互斥鎖函數(shù)參數(shù):參數(shù)mutex是互斥量,attr為互斥鎖屬性。返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。。函數(shù)說明:mutex為要鎖住的互斥量,attr是互斥鎖的屬性。如果要使用默認(rèn)的屬性初始化互斥量,只需把a(bǔ)ttr設(shè)置為NULL。(2)互斥量加鎖函數(shù)對(duì)共享資源的訪問,要對(duì)互斥量進(jìn)行加鎖,如果互斥量已經(jīng)上了鎖,調(diào)用線程會(huì)阻塞,直到互斥量被解鎖。在完成了對(duì)共享資源的訪問后,要對(duì)互斥量進(jìn)行解鎖?;コ饬考渔i函數(shù)原型如下:#include<pthread.h>int

pthread_mutex_lock(pthread_mutex_t*mutex);int

pthread_mutex_trylock(pthread_mutex_t*mutex);函數(shù)參數(shù):參數(shù)mutex是互斥量返回值:成功則返回0,出錯(cuò)則返回錯(cuò)誤編號(hào)函數(shù)說明:trylock函數(shù),這個(gè)函數(shù)是非阻塞調(diào)用模式,也就是說,如果互斥量沒被鎖住,trylock函數(shù)將把互斥量加鎖,并獲得對(duì)共享資源的訪問權(quán)限;如果互斥量被鎖住了,trylock函數(shù)將不會(huì)阻塞等待而直接返回EBUSY,表示共享資源處于忙狀態(tài)。(3)互斥量解鎖函數(shù)函數(shù)原型:#include<pthread.h>int

pthread_mutex_unlock(pthread_mutex_t*mutex);函數(shù)參數(shù):參數(shù)mutex是互斥量返回值:成功則返回0,出錯(cuò)則返回錯(cuò)誤編號(hào)對(duì)互斥量進(jìn)行加鎖,需要調(diào)用pthread_mutex_lock,如果互斥量已經(jīng)上鎖,調(diào)用線程阻塞直至互斥量解鎖。對(duì)互斥量解鎖,需要調(diào)用pthread_mutex_unlock.

如果線程不希望被阻塞,可以使用pthread_mutex_trylock嘗試對(duì)互斥量進(jìn)行加鎖。如果調(diào)用pthread_mutex_trylock時(shí)互斥量處于未鎖住狀態(tài),那么pthread_mutex_trylock將鎖住互斥量,否則就會(huì)失敗,不能鎖住互斥量,而返回EBUSY。例

7.9對(duì)互斥量加鎖#inlcude<stdio.h>#include<pthread.h>#inlcude<stdio.h>#include<unistd.h>void*thread_function(void*arg);int

run_now=1;/*用run_now代表共享資源*/intmain(){intprint_count1=0;/*用于控制循環(huán)*/pthread_t

a_thread;if(pthread_create(&a_thread,NULL,thread_function,NULL)!=0)/*創(chuàng)建一個(gè)線程*/{

perror(“Thread

createionfailed”);exit(1);}while(print_count1++<5){if(run_now==1)/*主線程:如果run_now為1就把它修改為2*/{printf(“mainthreadisrun\n”);

run_now=2;}else{printf(“mainthreadissleep\n”);sleep(1);}}pthread_join(a_thread,NULL);/*等待子線程結(jié)束*/exit(0);}void*thread_function(void*arg){intprint_count2=0;while(print_count2++<5){

if(run_now==2)/子線程:如果run_now為2就把它修改為1*/{printf(“functionthreadisrun\n”);

run_now=1;}else{

printf(“functionthreadissleep\n”);sleep(1);}}pthread_exit(NULL);}運(yùn)行上面程序的運(yùn)行結(jié)果為:functionthreadissleepmainthreadisrunmainthreadissleepmainthreadissleepfunctionthreadisrunfunctionthreadissleepmainthreadisrunmainthreadissleepfunctionthreadisrunfunctionthreadissleep可以看到main線程和function線程是交替運(yùn)行的。它們都可以對(duì)run_now進(jìn)行操作。例7.10下面是加鎖的程序。#inlcude<stdio.h>#include<pthread.h>#inlcude<stdio.h>viid*thread_function(void*arg);int

run_now=1;/*用run_now代表共享資源*/pthread_mutex_t

work_mutex;/*定義互斥量*/intmain(){intres;intprint_count1=0;prhread_t

a_thread;if(pthread_mutex_init(&work_mutex,NULL)!=0)/*初始化互斥量*/{perror(“Mutexinitfaied”);exit(1);}if(pthread_create(&a_thread,NULL,thread_function,NULL)!=0)/*創(chuàng)建新線程*/{perror(“Thread

createionfailed”);exit(1);}if(pthread_mutex_lock(&work_mutex)!=0)/*對(duì)互斥量加鎖*/{

preeor(“Lockfailed”);exit(1);}else

printf(“mainlock\n”);while(print_count1++<5){if(run_now==1)/主線程:如果run_now為1就把它修改為2*/{printf(“mainthreadisrun\n”);

run_now=2;}else{printf(“mainthreadissleep\n”);sleep(1);}}if(pthread_mutex_unlock(&work_mutex)!=0)/*對(duì)互斥量解鎖*/{preeor(“unlockfailed”);exit(1);}else

printf(“mainunlock\n”);pthread_mutex_destroy(&work_mutex);/*收回互斥量資源*/pthread_join(a_thread,NULL);/*等待子線程結(jié)束*/exit(0);}void*thread_function(void*arg){intprint_count2=0;sleep(1);if(pthread_mutex_lock(&work_mutex)!=0){perror(“Lockfailed”);exit(1);}else

printf(“functionlock\n”);while(print_count2++<5){if(run_now==2)/分進(jìn)程:如果run_now為1就把它修改為1*/{printf(“functionthreadisrun\n”);

run_now=1;}else{printf(“functionthreadissleep\n”);sleep(1);}}if(pthread_mutex_unlock(&work_mutex)!=0)/*對(duì)互斥量解鎖*/{perror(“unlockfailed”);exit(1);}else

printf(“functionunlock\n”);pthread_exit(NULL);}下面是運(yùn)行結(jié)果:mainlockmainthreadisrunmainthreadissleepmainthreadissleepmainthreadissleepmainthreadissleepmainunlockfunctionlockfunctionthreadisrunfunctionthreadissleepfunctionthreadissleepfunctionthreadissleepfunctionthreadissleepfunctionunlock2.互斥鎖屬性線程和線程的同步對(duì)象(互斥量,讀寫鎖,條件變量)都具有屬性。在修改屬性前都需要對(duì)該結(jié)構(gòu)進(jìn)行初始化。使用后要把該結(jié)構(gòu)回收。用pthread_mutexattr_init函數(shù)對(duì)pthread_mutexattr結(jié)構(gòu)進(jìn)行初始化。用pthread_mutexattr_destroy函數(shù)對(duì)該結(jié)構(gòu)進(jìn)行回收。(1)pthread_mutexattr_init/pthread_mutexattr_destroy函數(shù)用于初始化/回收pthread_mutexattr_t結(jié)構(gòu)。其函數(shù)原型如下:#include<pthread.h>int

pthread_mutexattrattr_init(pthread_mutexattr_t*attr);int

pthread_mutexattrattr_destroy(pthread_mutexattr_t*attr);函數(shù)參數(shù):pthread_mutexattr_t結(jié)構(gòu)變量,attr為互斥鎖屬性。返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。。函數(shù)說明:pthread_mutexattr_init將屬性對(duì)象的值初始化為缺省值。并分配屬性對(duì)象占用的內(nèi)存空間。參數(shù)attr中pshared屬性表示用這個(gè)屬性對(duì)象創(chuàng)建的互斥鎖的作用域,它的取值可以是PTHREAD_PROCESS_PRIVATE(缺省值該屬性對(duì)象創(chuàng)建的互斥鎖只能在進(jìn)程內(nèi)使用)或PTHREAD_PROCESS_SHARED。(2)pthread_mutexattr_getpshared/pthread_mutexattr_setpshared函數(shù)用于獲得/修改共享互斥量屬性。其函數(shù)原型如下:

#include<pthread.h>

int

pthread_mutexattrattr_getpshared(constpthread_attr_t*restrictattr,int*restrictpshared);

int

pthread_mutexattrattr_setpshared(constpthread_attr_t*restrictattr,int

pshared);

返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。函數(shù)說明:互斥量屬性分為共享互斥量屬性和類型互斥量屬性。兩種屬性分別由不同的函數(shù)得到并由不同的函數(shù)進(jìn)行修改。pthread_mutexattr_getpshared/pthread_mutexattr_setpshared函數(shù)可以獲得和修改共享互斥量屬性。pthread_mutexattr_gettype和pthread_mutexattr_settype函數(shù)可以獲得和修改類型互斥量屬性。

共享互斥量屬性用于規(guī)定互斥鎖的作用域?;コ怄i的域可以是進(jìn)程內(nèi)的也可以是進(jìn)程間的。pthread_mutexattrattr_getpshared可以返回屬性對(duì)象的互斥鎖作用域?qū)傩?。可是以下值:PTHREAD_PROCESS_SHARED,PTHREAD_PROCESS_PRIVATE。如果互斥鎖屬性對(duì)象的pshared屬性被置PTHREAD_PROCESS_SHARED。那么由這個(gè)屬性對(duì)象創(chuàng)建的互斥鎖將被保存在共享內(nèi)存中,可以被多個(gè)進(jìn)程中的線程共享。如果pshared屬性被置為PTHREAD_PROCESS_PRIVATE,那么只有和創(chuàng)建這個(gè)互斥鎖的線程在同一個(gè)進(jìn)程中的線程才能訪問這個(gè)互斥鎖。

(3)pthread_mutexattr_gettype/pthread_mutexattr_settype

函數(shù)用于獲得/修改類型互斥量屬性。其函數(shù)原型如下:

#include<pthread.h>

int

pthread_mutexattr_gettype(pthread_mutexattr_t*attr,int*type);

int

pthread_mutexattr_settype(pthread_mutexattr_t*attr,inttype);返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。。函數(shù)說明:pthread_mutexattr_gettype函數(shù)可以獲得互斥鎖類型屬性,pthread_mutexattr_settype函數(shù)可用來設(shè)置互斥鎖的type屬性。缺省的互斥鎖類型屬性是PTHREAD_MUTEX_DEFAULT。合法的類型屬性值有:PTHREAD_MUTEX_NORMAL;PTHREAD_MUTEX_ERRORCHECK;PTHREAD_MUTEX_RECURSIVE;PTHREAD_MUTEX_DEFAULT。類型說明:①PTHREAD_MUTEX_NORMAL這種類型的互斥鎖不會(huì)自動(dòng)檢測(cè)死鎖。如果一個(gè)線程試圖對(duì)一個(gè)互斥鎖重復(fù)鎖定,將會(huì)引起這個(gè)線程的死鎖。如果試圖解鎖一個(gè)由別的線程鎖定的互斥鎖會(huì)引發(fā)不可預(yù)料的結(jié)果。如果一個(gè)線程試圖解鎖已經(jīng)被解鎖的互斥鎖也會(huì)引發(fā)不可預(yù)料的結(jié)果。②PTHREAD_MUTEX_ERRORCHECK這種類型的互斥鎖會(huì)自動(dòng)檢測(cè)死鎖。若一個(gè)線程試圖對(duì)一個(gè)互斥鎖重復(fù)鎖定,則返回錯(cuò)誤代碼。若試圖解鎖一個(gè)由別的線程鎖定的互斥鎖,則返回錯(cuò)誤代碼。若一個(gè)線程試圖解鎖已經(jīng)被解鎖的互斥鎖,則返回錯(cuò)誤代碼。③PTHREAD_MUTEX_RECURSIVE一個(gè)線程對(duì)這種類型的互斥鎖重復(fù)上鎖,不會(huì)引起死鎖,一個(gè)線程對(duì)這類互斥鎖的多次重復(fù)上鎖必須由這個(gè)線程來重復(fù)相同數(shù)量的解鎖,否則別的線程不能得到這個(gè)互斥鎖。試圖解鎖一個(gè)由別的線程鎖定的互斥鎖將會(huì)返回錯(cuò)誤代碼。一個(gè)線程試圖解鎖已經(jīng)被解鎖的互斥鎖也將會(huì)返回錯(cuò)誤代碼。這種類型的互斥鎖只能是進(jìn)程私有的(作用域?qū)傩詾門HREAD_PROCESS_PRIVATE)。④PTHREAD_MUTEX_DEFAULT

這種類型的互斥鎖不會(huì)自動(dòng)檢測(cè)死鎖。如果一個(gè)線程試圖對(duì)一個(gè)互斥鎖重復(fù)鎖定,將會(huì)引起不可預(yù)料的結(jié)果。如果試圖解鎖一個(gè)由別的線程鎖定的互斥鎖會(huì)引發(fā)不可預(yù)料的結(jié)果。如果一個(gè)線程試圖解鎖已經(jīng)被解鎖的互斥鎖也會(huì)引發(fā)不可預(yù)料的結(jié)果。POSIX標(biāo)準(zhǔn)規(guī)定,對(duì)于某一具體的實(shí)現(xiàn),可以把這種類型的互斥鎖定義為其他類型的互斥鎖。應(yīng)用互斥量需要注意的幾點(diǎn):(1)互斥量需要時(shí)間來加鎖和解鎖。鎖住較少互斥量的程序通常運(yùn)行得更快。所以,互斥量應(yīng)該盡量少,夠用即可,每個(gè)互斥量保護(hù)的區(qū)域應(yīng)則盡量大。(2)互斥量的本質(zhì)是串行執(zhí)行。如果很多線程需要領(lǐng)繁地加鎖同一個(gè)互斥量,則線程的大部分時(shí)間就會(huì)在等待,這對(duì)性能是有害的。如果互斥量保護(hù)的數(shù)據(jù)(或代碼)包含彼此無關(guān)的片段,則可以特大的互斥量分解為幾個(gè)小的互斥量來提高性能。這樣,任意時(shí)刻需要小互斥量的線程減少,線程等待時(shí)間就會(huì)減少。所以,互斥量應(yīng)該足夠多(到有意義的地步),每個(gè)互斥量保護(hù)的區(qū)域則應(yīng)盡量的少。

7.4條件變量與互斥鎖不同,條件變量是用來等待而不是用來上鎖的。條件變量用來自動(dòng)阻塞一個(gè)線程,直到某特殊情況發(fā)生為止。通常條件變量和互斥鎖同時(shí)使用。條件變量可以睡眠等待某種條件出現(xiàn)。條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個(gè)動(dòng)作:一個(gè)線程等待"條件變量的條件成立"而掛起;另一個(gè)線程使“條件成立”(給出條件成立信號(hào))。條件的檢測(cè)是在互斥鎖的保護(hù)下進(jìn)行的。如果一個(gè)條件為假,一個(gè)線程自動(dòng)阻塞,并釋放等待狀態(tài)改變的互斥鎖。如果另一個(gè)線程改變了條件,它發(fā)信號(hào)給關(guān)聯(lián)的條件變量,喚醒一個(gè)或多個(gè)等待它的線程,重新獲得互斥鎖,重新評(píng)價(jià)條件。如果兩進(jìn)程共享可讀寫的內(nèi)存,條件變量可以被用來實(shí)現(xiàn)這兩進(jìn)程間的線程。1.初始化條件變量屬性使用pthread_condattr_init函數(shù)可以將與該對(duì)象相關(guān)聯(lián)的屬性初始化為其缺省值。在執(zhí)行過程中,線程系統(tǒng)會(huì)為每個(gè)屬性對(duì)象分配存儲(chǔ)空間。其函數(shù)原型如下:#include<pthread.h>int

pthread_condattr_init(pthread_condattr_t*attr);返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào),錯(cuò)誤碼為ENOMEM,表示分配的內(nèi)存不足,無法初始化線程屬性對(duì)象;錯(cuò)誤碼為EINVAL表示attr

指定的值無效。函數(shù)說明:函數(shù)調(diào)用時(shí),pshared

屬性的缺省值為PTHREAD_PROCESS_PRIVATE,表示可以在進(jìn)程內(nèi)使用已初始化的條件變量。attr

的數(shù)據(jù)類型為pthread_condattr_t,其中包含一個(gè)由系統(tǒng)分配的屬性對(duì)象。attr

范圍可能的值為PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。2.刪除條件變量屬性使用pthread_condattr_destroy函數(shù)可以刪除存儲(chǔ)并使屬性對(duì)象無效。其函數(shù)原型如下:#include<pthread.h>int

pthread_condattr_destroy(pthread_condattr_t*attr);返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。函數(shù)說明:條件變量屬性必須首先由pthread_condattr_destroy函數(shù)刪除條件變量屬性后,重新初始化后才能重用。3.設(shè)置條件變量的范圍pthread_condattr_setpshared函數(shù)可用來將條件變量的范圍設(shè)置為進(jìn)程專用(進(jìn)程內(nèi))或系統(tǒng)范圍內(nèi)(進(jìn)程間)。其函數(shù)原型如下:#include<pthread.h>Int

pthread_condattr_setpshared(pthread_condattr_t*cattr,int

pshared);返回值:若函數(shù)調(diào)用成功則返回0,否則返回錯(cuò)誤編號(hào)。函數(shù)說明:條件變量屬性必須首先由pthread_condattr_destroy函數(shù)刪除條件變量屬性重新初始化后才能重用。例如:ret=pthread_condattr_setpshared(&cattr,PTHREAD_PROCESS_SHARED);或ret=pthread_condattr_setpshared(&cattr,PTHREAD_PROCESS_PRIVATE);如果pshared

屬性在共享內(nèi)存中設(shè)置為PTHREAD_PROCESS_SHARED,則其所創(chuàng)建的條件變量可以在多個(gè)進(jìn)程中的線程之間共享。此行為與最初的Solaris線程實(shí)現(xiàn)中mutex_init()中的USYNC_PROCESS標(biāo)志等效。如果互斥鎖的pshared

屬性設(shè)置為PTHREAD_PROCESS_PRIVATE,則僅有那些由同一個(gè)進(jìn)程創(chuàng)建的線程才能夠處理該互斥鎖。PTHREAD_PROCESS_PRIVATE是缺省值。PTHREAD_PROCESS_PRIVATE所產(chǎn)生的行為與在最初的Solaris線程的cond_init()調(diào)用中使用USYNC_THREAD標(biāo)志相同。PTHREAD_PROCESS_PRIVATE的行為與局部條件變量相同。

4.獲取條件變量的范圍pthread_condattr_getpshared函數(shù)可用來獲取屬性對(duì)象cattr

的pshared

的當(dāng)前值。其函數(shù)原型如下:#include<pthread.h>int

pthread_condattr_getpshared(const

pthread_condattr_t*cattr,in

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論