淺析pthread_cond_wait
條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個(gè)動(dòng)作:一個(gè)線程等待"條件變量的條件成立"而掛起;另一個(gè)線程使"條件成立"(給出條件成立信號)。為了防止競爭,條件變量的使用總是和一個(gè)互斥鎖結(jié)合在一起。
一 pthread_cond_wait定義:
函數(shù)原型:int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
參數(shù): cond 條件變量 mutex 互斥鎖
第一個(gè)參數(shù)*cond是指向一個(gè)條件變量的指針。第二個(gè)參數(shù)*mutex則是對相關(guān)的互斥鎖的指針。
二 pthread_cond_wait示例理解
pthread_cond_wait的機(jī)制比較難里理解,是條件變量中重要的成分。條件變量用于線程間同步,那么pthread_cond_wait必須和互斥鎖同時(shí)作用在一個(gè)線程里,它同時(shí)起到對資源的加鎖和解鎖,看下面的示例:
程序創(chuàng)建了2個(gè)新線程使他們同步運(yùn)行,實(shí)現(xiàn)進(jìn)程t_b打印9以內(nèi)3的倍數(shù),t_a打印其他的數(shù),程序開始線程t_b不滿足條件等待,線程t_a運(yùn)行使a循環(huán)加1并打印。直到i為3的倍數(shù)時(shí),線程t_a發(fā)送信號通知進(jìn)程t_b,這時(shí)t_b滿足條件,打印i值。
- 1 #include<pthread.h>
- 2 #include<unistd.h>
- 3 #include<stdio.h>
- 4 #include<stdlib.h>
- 5
- 6 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- 7 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 8
- 9 void *thread1(void*);
- 10 void *thread2(void*);
- 11
- 12 int i = 1;
- 13
- 14 int main(void){
- 15 pthread_t t_a;
- 16 pthread_t t_b;
- 17
- 18 pthread_create(&t_a,NULL,thread2,(void*)NULL);
- 19 pthread_create(&t_b,NULL,thread1,(void*)NULL);
- 20
- 21 pthread_join(t_b,NULL);
- 22 pthread_mutex_destroy(&mutex);
- 23 pthread_cond_destroy(&cond);
- 24 exit(0);
- 25 }
- 26
- 27 void *thread1(void *junk){
- 28 for(i = 1;i<= 9; i++){
- 29 pthread_mutex_lock(&mutex);
- 30 printf("call thread1 \n");
- 31 if(i%3 == 0)
- 32 pthread_cond_signal(&cond);
- 33 else
- 34 printf("thread1: %d\n",i);
- 35 pthread_mutex_unlock(&mutex);
- 36 sleep(1);
- 37 }
- 38 }
- 39
- 40 void *thread2(void*junk){
- 41 while(i < 9)
- 42 {
- 43 pthread_mutex_lock(&mutex);
- 44 printf("call thread2 \n");
- 45 if(i%3 != 0)
- 46 pthread_cond_wait(&cond,&mutex);
- 47 printf("thread2: %d\n",i);
- 48 pthread_mutex_unlock(&mutex);
- 49 sleep(1);
- 50 }
- 51 }
輸出:
call thread2
call thread1
thread1: 1
call thread1
thread1: 2
call thread1
thread2: 3
call thread1
thread1: 4
call thread2
call thread1
thread1: 5
call thread1
thread2: 6
call thread1
thread1: 7
call thread2
call thread1
thread1: 8
call thread1
thread2: 9
示例的解釋:
call thread2:是線程2即t_b首先上鎖,即 pthread_mutex_lock(&mutex);鎖住了mutex使得此進(jìn)程執(zhí)行線程2中的臨界區(qū)的代碼,當(dāng)執(zhí)行到45行:if(i%3 != 0),此時(shí)i=1,滿足此條件,則執(zhí)行46行: pthread_cond_wait(&cond,&mutex); 這句是關(guān)鍵,pthread_cond_wait(&cond,&mutex)操作有兩步,是原子操作:第一 解鎖,先解除之前的pthread_mutex_lock鎖定的mutex;第二 掛起,阻塞并在等待對列里休眠,即線程2掛起,直到再次被喚醒,喚醒的條件是由pthread_cond_signal(&cond);發(fā)出的cond信號來喚醒。
call thread1:由于pthread_cond_wait已經(jīng)對線程2解鎖,此時(shí)另外的線程只有線程1,那么線程1對mutex上鎖,若這時(shí)有多個(gè)線程,那么線程間上鎖的順序和操作系統(tǒng)有關(guān)。
thread1: 1:線程1上鎖后執(zhí)行臨界區(qū)的代碼,當(dāng)執(zhí)行到if(i%3 == 0)此時(shí)i=1,不滿足條件,則pthread_cond_signal(&cond);不被執(zhí)行,那么線程2仍處于掛起狀態(tài),輸出thread1: 1后線程1由pthread_mutex_unlock(&mutex);解鎖。
thread1: 2:這時(shí)此進(jìn)程中只有2個(gè)線程,線程2處于掛起狀態(tài),那么只有線程1,則線程1又對mutex上鎖,此時(shí)同樣執(zhí)行臨界區(qū)的代碼,而且i=2,不滿足條件,pthread_cond_signal(&cond);不被執(zhí)行,那么線程2仍處于掛起狀態(tài),輸出thread1: 1后線程1由pthread_mutex_unlock(&mutex);解鎖。
call thread1:同樣由線程1上鎖,但此時(shí)i=3,滿足條件pthread_cond_signal(&cond)被執(zhí)行,那么pthread_cond_signal(&cond)會(huì)發(fā)出信號,來喚醒處于掛起的線程2。pthread_cond_signal同樣由兩個(gè)原子操作:1,解鎖;2,發(fā)送信號;解鎖即對線程1解鎖,解除對mutex的上鎖。發(fā)送信號,即給等待signal掛起的線程2發(fā)送信號,喚醒掛起的線程2。
thread2: 3:由于pthread_cond_signal喚醒了線程2,即i=3滿足條件,pthread_cond_wait(&cond,&mutex);被執(zhí)行,那么pthread_cond_wait(&cond,&mutex)此時(shí)也有一步操作:上鎖;即對線程2上鎖,此時(shí)的pthread_cond_wait(&cond,&mutex)的操作相當(dāng)與pthread_mutex_lock(&mutex);那么線程2繼續(xù)執(zhí)行上鎖后的臨界區(qū)的代碼,并由pthread_mutex_unlock(&mutex);對線程2進(jìn)行解鎖。
剩下的輸出原理和上面解釋的一樣。
縱觀pthread_cond_wait,它的理解不可之把它看作一個(gè)簡單的wait函數(shù),它里面應(yīng)該是一族函數(shù),不同的函數(shù)在不同的條件下執(zhí)行,理解pthread_cond_wait的機(jī)制可以很好的學(xué)習(xí)條件變量。