




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Linux下提供了多種方式來(lái)處理線程同步,最常用的是互斥鎖、條件變量和信號(hào)量。一、互斥鎖(mutex)鎖機(jī)制是同一時(shí)刻只允許一個(gè)線程執(zhí)行一個(gè)關(guān)鍵部分的代碼。1. 初始化鎖int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr); 其中參數(shù) mutexattr 用于指定鎖的屬性(見(jiàn)下),如果為NULL則使用缺省屬性。 互斥鎖的屬性在創(chuàng)建鎖的時(shí)候指定,在LinuxThreads實(shí)現(xiàn)中僅有一個(gè)鎖類(lèi)型屬性,不同的鎖類(lèi)型在試圖對(duì)一個(gè)已經(jīng)被鎖定的互斥鎖加鎖時(shí)表現(xiàn)不同。當(dāng)前有四個(gè)值可供選擇: (1
2、)PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當(dāng)一個(gè)線程加鎖以后,其余請(qǐng)求鎖的線程將形成一個(gè)等待隊(duì)列,并在解鎖后按優(yōu)先級(jí)獲得鎖。這種鎖策略保證了資源分配的公平性。 (2)PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一個(gè)線程對(duì)同一個(gè)鎖成功獲得多次,并通過(guò)多次unlock解鎖。如果是不同線程請(qǐng)求,則在加鎖線程解鎖時(shí)重新競(jìng)爭(zhēng)。 (3)PTHREAD_MUTEX_ERRORCHECK_NP,檢錯(cuò)鎖,如果同一個(gè)線程請(qǐng)求同一個(gè)鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類(lèi)型動(dòng)作相同。這樣就保證當(dāng)不允許多次加鎖時(shí)不會(huì)出現(xiàn)最簡(jiǎn)
3、單情況下的死鎖。 (4)PTHREAD_MUTEX_ADAPTIVE_NP,適應(yīng)鎖,動(dòng)作最簡(jiǎn)單的鎖類(lèi)型,僅等待解鎖后重新競(jìng)爭(zhēng)。2. 阻塞加鎖int pthread_mutex_lock(pthread_mutex *mutex);3. 非阻塞加鎖 int pthread_mutex_trylock( pthread_mutex_t *mutex); 該函數(shù)語(yǔ)義與 pthread_mutex_lock() 類(lèi)似,不同的是在鎖已經(jīng)被占據(jù)時(shí)返回 EBUSY 而不是掛起等待。4. 解鎖(要求鎖是lock狀態(tài),并且由加鎖線程解鎖)int pthread_mutex_unlock(pthread_mute
4、x *mutex);5. 銷(xiāo)毀鎖(此時(shí)鎖必需unlock狀態(tài),否則返回EBUSY)int pthread_mutex_destroy(pthread_mutex *mutex);示例代碼:oraclelocalhost$ cat mutextest.c#include #include #include #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int gn;void* thread(void *arg) printf(threads ID is %dn,pthread_self(); pthread_mutex_lo
5、ck(&mutex); gn = 12; printf(Now gn = %dn,gn); pthread_mutex_unlock(&mutex); return NULL;int main() pthread_t id; printf(main threads ID is %dn,pthread_self(); gn = 3; printf(In main func, gn = %dn,gn); if (!pthread_create(&id, NULL, thread, NULL) printf(Create thread success!n); else printf(Create t
6、hread failed!n); pthread_join(id, NULL); pthread_mutex_destroy(&mutex); return 0;oraclelocalhost$二、條件變量(cond)條件變量是利用線程間共享全局變量進(jìn)行同步的一種機(jī)制。條件變量上的基本操作有:觸發(fā)條件(當(dāng)條件變?yōu)?true 時(shí));等待條件,掛起線程直到其他線程觸發(fā)條件。 1. 初始化條件變量 int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr); 盡管POSIX標(biāo)準(zhǔn)中為條件變量定義了屬性,但在Linu
7、x中沒(méi)有實(shí)現(xiàn),因此cond_attr值通常為NULL,且被忽略。 2. 有兩個(gè)等待函數(shù) (1)無(wú)條件等待 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); (2)計(jì)時(shí)等待 int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime); 如果在給定時(shí)刻前條件沒(méi)有滿足,則返回ETIMEOUT,結(jié)束等待,其中abstime以與time()系統(tǒng)調(diào)用相同意義的絕對(duì)時(shí)間形式出現(xiàn),0表示格林尼治時(shí)間1
8、970年1月1日0時(shí)0分0秒。 無(wú)論哪種等待方式,都必須和一個(gè)互斥鎖配合,以防止多個(gè)線程同時(shí)請(qǐng)求(用 pthread_cond_wait() 或 pthread_cond_timedwait() 請(qǐng)求)競(jìng)爭(zhēng)條件(Race Condition)。mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者適應(yīng)鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調(diào)用pthread_cond_wait()前必須由本線程加鎖(pthread_mutex_lock()),而在更新條件等待隊(duì)列以前,mutex保持鎖定狀態(tài),并在線程掛起進(jìn)入等待前解鎖。在條件滿足從而離開(kāi)pthr
9、ead_cond_wait()之前,mutex將被重新加鎖,以與進(jìn)入pthread_cond_wait()前的加鎖動(dòng)作對(duì)應(yīng)。 3. 激發(fā)條件 (1)激活一個(gè)等待該條件的線程(存在多個(gè)等待線程時(shí)按入隊(duì)順序激活其中一個(gè)) int pthread_cond_signal(pthread_cond_t *cond); (2)激活所有等待線程 int pthread_cond_broadcast(pthread_cond_t *cond); 4. 銷(xiāo)毀條件變量 int pthread_cond_destroy(pthread_cond_t *cond); 只有在沒(méi)有線程在該條件變量上等待的時(shí)候才能銷(xiāo)毀這
10、個(gè)條件變量,否則返回EBUSY說(shuō)明:1. pthread_cond_wait 自動(dòng)解鎖互斥量(如同執(zhí)行了pthread_unlock_mutex),并等待條件變量觸發(fā)。這時(shí)線程掛起,不占用CPU時(shí)間,直到條件變量被觸發(fā)(變量為ture)。在調(diào)用 pthread_cond_wait之前,應(yīng)用程序必須加鎖互斥量。pthread_cond_wait函數(shù)返回前,自動(dòng)重新對(duì)互斥量加鎖(如同執(zhí)行了pthread_lock_mutex)。2. 互斥量的解鎖和在條件變量上掛起都是自動(dòng)進(jìn)行的。因此,在條件變量被觸發(fā)前,如果所有的線程都要對(duì)互斥量加鎖,這種機(jī)制可保證在線程加鎖互斥量和進(jìn)入等待條件變量期間,條件變量
11、不被觸發(fā)。條件變量要和互斥量相聯(lián)結(jié),以避免出現(xiàn)條件競(jìng)爭(zhēng)個(gè)線程預(yù)備等待一個(gè)條件變量,當(dāng)它在真正進(jìn)入等待之前,另一個(gè)線程恰好觸發(fā)了該條件(條件滿足信號(hào)有可能在測(cè)試條件和調(diào)用pthread_cond_wait函數(shù)(block)之間被發(fā)出,從而造成無(wú)限制的等待)。3. 條件變量函數(shù)不是異步信號(hào)安全的,不應(yīng)當(dāng)在信號(hào)處理程序中進(jìn)行調(diào)用。特別要注意,如果在信號(hào)處理程序中調(diào)用 pthread_cond_signal 或 pthread_cond_boardcast 函數(shù),可能導(dǎo)致調(diào)用線程死鎖示例代碼1:oraclelocalhost$ cat condtest1.c#include #include #inc
12、lude stdlib.h#include unistd.hpthread_mutex_t mutex;pthread_cond_t cond;void hander(void *arg) free(arg); (void)pthread_mutex_unlock(&mutex);void *thread1(void *arg) pthread_cleanup_push(hander, &mutex); while(1) printf(thread1 is runningn); pthread_mutex_lock(&mutex); pthread_cond_wait(&cond,&mutex
13、); printf(thread1 applied the conditionn); pthread_mutex_unlock(&mutex); sleep(4); pthread_cleanup_pop(0);void *thread2(void *arg) while(1) printf(thread2 is runningn); pthread_mutex_lock(&mutex); pthread_cond_wait(&cond,&mutex); printf(thread2 applied the conditionn); pthread_mutex_unlock(&mutex);
14、sleep(1); int main() pthread_t thid1,thid2; printf(condition variable study!n); pthread_mutex_init(&mutex,NULL); pthread_cond_init(&cond,NULL); pthread_create(&thid1,NULL,thread1,NULL); pthread_create(&thid2,NULL,thread2,NULL); sleep(1); do pthread_cond_signal(&cond); while(1); sleep(20); pthread_ex
15、it(0); return 0;oraclelocalhost$示例代碼2:oraclelocalhost$ cat condtest2.c#include #include #include stdio.h#include stdlib.hstatic pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;struct node int n_number; struct node *n_next;*head = NULL;static void
16、 cleanup_handler(void *arg) printf(Cleanup handler of second thread.n); free(arg); (void)pthread_mutex_unlock(&mtx);static void *thread_func(void *arg) struct node *p = NULL; pthread_cleanup_push(cleanup_handler, p); while (1) / 這個(gè)mutex主要是用來(lái)保證pthread_cond_wait的并發(fā)性。 pthread_mutex_lock(&mtx); while (h
17、ead = NULL) /* 這個(gè)while要特別說(shuō)明一下,單個(gè)pthread_cond_wait功能很完善,為何 * 這里要有一個(gè)while (head = NULL)呢?因?yàn)閜thread_cond_wait里的線 * 程可能會(huì)被意外喚醒,如果這個(gè)時(shí)候head != NULL,則不是我們想要的情況。 * 這個(gè)時(shí)候,應(yīng)該讓線程繼續(xù)進(jìn)入pthread_cond_wait * pthread_cond_wait會(huì)先解除之前的pthread_mutex_lock鎖定的mtx, * 然后阻塞在等待對(duì)列里休眠,直到再次被喚醒(大多數(shù)情況下是等待的條件成立 * 而被喚醒,喚醒后,該進(jìn)程會(huì)先鎖定先pthr
18、ead_mutex_lock(&mtx);,再讀取資源 * 用這個(gè)流程是比較清楚的。*/ pthread_cond_wait(&cond, &mtx); p = head; head = head-n_next; printf(Got %d from front of queuen, p-n_number); free(p); pthread_mutex_unlock(&mtx); / 臨界區(qū)數(shù)據(jù)操作完畢,釋放互斥鎖。 pthread_cleanup_pop(0); return 0;int main(void) pthread_t tid; int i; struct node *p; /*
19、 子線程會(huì)一直等待資源,類(lèi)似生產(chǎn)者和消費(fèi)者,但是這里的消費(fèi)者可以是多個(gè)消費(fèi)者, * 而不僅僅支持普通的單個(gè)消費(fèi)者,這個(gè)模型雖然簡(jiǎn)單,但是很強(qiáng)大。*/ pthread_create(&tid, NULL, thread_func, NULL); sleep(1); for (i = 0; i n_number = i; pthread_mutex_lock(&mtx); / 需要操作head這個(gè)臨界資源,先加鎖。 p-n_next = head; head = p; pthread_cond_signal(&cond); pthread_mutex_unlock(&mtx); /解鎖 sleep
20、(1); printf(thread 1 wanna end the line.So cancel thread 2.n); /* 關(guān)于pthread_cancel,有一點(diǎn)額外的說(shuō)明,它是從外部終止子線程,子線程會(huì)在最近的取消點(diǎn), * 退出線程,而在我們的代碼里,最近的取消點(diǎn)肯定就是pthread_cond_wait()了。*/ pthread_cancel(tid); pthread_join(tid, NULL); printf(All done - exitingn); return 0;oraclelocalhost$可以看出,等待條件變量信號(hào)的用法約定一般是這樣的:.pthread_
21、mutex_lock(&mutex);.pthread_cond_wait (&cond, &mutex);.pthread_mutex_unlock (&mutex);.相信很多人都會(huì)有這個(gè)疑問(wèn):為什么pthread_cond_wait需要的互斥鎖不在函數(shù)內(nèi)部定義,而要使用戶(hù)定義的呢?現(xiàn)在沒(méi)有時(shí)間研究 pthread_cond_wait 的源代碼,帶著這個(gè)問(wèn)題對(duì)條件變量的用法做如下猜測(cè),希望明白真相看過(guò)源代碼的朋友不吝指正。1. pthread_cond_wait 和 pthread_cond_timewait 函數(shù)為什么需要互斥鎖?因?yàn)椋簵l件變量是線程同步的一種方法,這兩個(gè)函數(shù)又是等待信號(hào)
22、的函數(shù),函數(shù)內(nèi)部一定有須要同步保護(hù)的數(shù)據(jù)。2. 使用用戶(hù)定義的互斥鎖而不在函數(shù)內(nèi)部定義的原因是:無(wú)法確定會(huì)有多少用戶(hù)使用條件變量,所以每個(gè)互斥鎖都須要?jiǎng)討B(tài)定義,而且管理大量互斥鎖的開(kāi)銷(xiāo)太大,使用用戶(hù)定義的即靈活又方便,符合UNIX哲學(xué)的編程風(fēng)格(隨便推薦閱讀UNIX編程哲學(xué)這本好書(shū)?。?。3. 好了,說(shuō)完了1和2,我們來(lái)自由猜測(cè)一下 pthread_cond_wait 函數(shù)的內(nèi)部結(jié)構(gòu)吧: int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) if(沒(méi)有條件信號(hào)) (1)pthread_mutex_unlock (m
23、utex); / 因?yàn)橛脩?hù)在函數(shù)外面已經(jīng)加鎖了(這是使用約定),但是在沒(méi)有信號(hào)的情況下為了讓其他線程也能等待cond,必須解鎖。 (2) 阻塞當(dāng)前線程,等待條件信號(hào)(當(dāng)然應(yīng)該是類(lèi)似于中斷觸發(fā)的方式等待,而不是軟件輪詢(xún)的方式等待). 有信號(hào)就繼續(xù)執(zhí)行后面。 (3) pthread_mutex_lock (mutex); / 因?yàn)橛脩?hù)在函數(shù)外面要解鎖(這也是使用約定),所以要與1呼應(yīng)加鎖,保證用戶(hù)感覺(jué)依然是自己加鎖、自己解鎖。 . 三、 信號(hào)量如同進(jìn)程一樣,線程也可以通過(guò)信號(hào)量來(lái)實(shí)現(xiàn)通信,雖然是輕量級(jí)的。 線程使用的基本信號(hào)量函數(shù)有四個(gè):#include 1. 初始化信號(hào)量 int sem_ini
24、t (sem_t *sem , int pshared, unsigned int value); 參數(shù): sem - 指定要初始化的信號(hào)量; pshared - 信號(hào)量 sem 的共享選項(xiàng),linux只支持0,表示它是當(dāng)前進(jìn)程的局部信號(hào)量; value - 信號(hào)量 sem 的初始值。 2. 信號(hào)量值加1 給參數(shù)sem指定的信號(hào)量值加1。 int sem_post(sem_t *sem); 3. 信號(hào)量值減1 給參數(shù)sem指定的信號(hào)量值減1。 int sem_wait(sem_t *sem); 如果sem所指的信號(hào)量的數(shù)值為0,函數(shù)將會(huì)等待直到有其它線程使它不再是0為止。 4. 銷(xiāo)毀信號(hào)量 銷(xiāo)
25、毀指定的信號(hào)量。int sem_destroy(sem_t *sem);示例代碼:oraclelocalhost$ cat semtest.c#include #include #include #include #include #include #define return_if_fail(p) if(p) = 0)printf (%s:func error!n, _func_);return;typedef struct _PrivInfo sem_t s1; sem_t s2; time_t end_time;PrivInfo;static void info_init (PrivIn
26、fo* prifo);static void info_destroy (PrivInfo* prifo);static void* pthread_func_1 (PrivInfo* prifo);static void* pthread_func_2 (PrivInfo* prifo);int main (int argc, char* argv) pthread_t pt_1 = 0; pthread_t pt_2 = 0; int ret = 0; PrivInfo* prifo = NULL; prifo = (PrivInfo* )malloc (sizeof (PrivInfo)
27、; if (prifo = NULL) printf (%s: Failed to malloc priv.n); return -1; info_init (prifo); ret = pthread_create (&pt_1, NULL, (void*)pthread_func_1, prifo); if (ret != 0) perror (pthread_1_create:); ret = pthread_create (&pt_2, NULL, (void*)pthread_func_2, prifo); if (ret != 0) perror (pthread_2_create:); pthread_join (pt_1, NULL); pthread_join (pt_2, NULL); info_
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 商鋪土方回填施工方案
- 商品房現(xiàn)房買(mǎi)賣(mài)合同
- 貸款申請(qǐng)資料清單表
- 土地股權(quán)轉(zhuǎn)讓合同
- 合同協(xié)議書(shū)意向書(shū)
- 湖州路基換填施工方案
- 鋁格柵幕墻施工方案
- 隨州金屬氟碳漆施工方案
- 外墻干掛鋁塑板施工方案
- 黑龍江省黑河市龍西北高中名校聯(lián)盟2024-2025學(xué)年高一下學(xué)期開(kāi)學(xué)英語(yǔ)試題(原卷版+解析版)
- 術(shù)前肺功能評(píng)估的意義
- 項(xiàng)目精細(xì)化管理檢查整改報(bào)告范文
- 分布式文件系統(tǒng)
- 手槍的基礎(chǔ)射擊演示文稿
- 浮針療法的學(xué)習(xí)課件
- 12K101-1 軸流通風(fēng)機(jī)安裝
- 上海市中小學(xué)生語(yǔ)文學(xué)業(yè)質(zhì)量綠色指標(biāo)測(cè)試
- 消防預(yù)留預(yù)埋施工【優(yōu)質(zhì)方案】
- 兩篇古典英文版成語(yǔ)故事畫(huà)蛇添足
- GB/T 21739-2008家用電梯制造與安裝規(guī)范
- 2023年杭州市余杭區(qū)事業(yè)單位招聘筆試題庫(kù)及答案解析
評(píng)論
0/150
提交評(píng)論