最近看《UNIX環境高級編程》多線程同步,看到他舉例說條件變量pthread_cond_t怎麼用,愣是沒有看懂,只好在網上找了份代碼,跑了跑,才弄明白
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥鎖*/
- pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化條件變量*/
- void *thread1(void *);
- void *thread2(void *);
- int i=1;
- int main(void)
- {
- pthread_t t_a;
- pthread_t t_b;
- pthread_create(&t_a,NULL,thread1,(void *)NULL);/*創建進程t_a*/
- pthread_create(&t_b,NULL,thread2,(void *)NULL); /*創建進程t_b*/
- pthread_join(t_a, NULL);/*等待進程t_a結束*/
- pthread_join(t_b, NULL);/*等待進程t_b結束*/
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond);
- exit(0);
- }
- void *thread1(void *junk)
- {
- for(i=1;i<=6;i++)
- {
- pthread_mutex_lock(&mutex);/*鎖住互斥量*/
- printf("thread1: lock %d/n", __LINE__);
- if(i%3==0){
- printf("thread1:signal 1 %d/n", __LINE__);
- pthread_cond_signal(&cond);/*條件改變,發送信號,通知t_b進程*/
- printf("thread1:signal 2 %d/n", __LINE__);
- sleep(1);
- }
- pthread_mutex_unlock(&mutex);/*解鎖互斥量*/
- printf("thread1: unlock %d/n/n", __LINE__);
- sleep(1);
- }
- }
- void *thread2(void *junk)
- {
- while(i<6)
- {
- pthread_mutex_lock(&mutex);
- printf("thread2: lock %d/n", __LINE__);
- if(i%3!=0){
- printf("thread2: wait 1 %d/n", __LINE__);
- pthread_cond_wait(&cond,&mutex);/*解鎖mutex,並等待cond改變*/
- printf("thread2: wait 2 %d/n", __LINE__);
- }
- pthread_mutex_unlock(&mutex);
- printf("thread2: unlock %d/n/n", __LINE__);
- sleep(1);
- }
- }
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥鎖*/
- pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化條件變量*/
- void *thread1(void *);
- void *thread2(void *);
- int i=1;
- int main(void)
- {
- pthread_t t_a;
- pthread_t t_b;
- pthread_create(&t_a,NULL,thread1,(void *)NULL);/*創建進程t_a*/
- pthread_create(&t_b,NULL,thread2,(void *)NULL); /*創建進程t_b*/
- pthread_join(t_a, NULL);/*等待進程t_a結束*/
- pthread_join(t_b, NULL);/*等待進程t_b結束*/
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond);
- exit(0);
- }
- void *thread1(void *junk)
- {
- for(i=1;i<=6;i++)
- {
- pthread_mutex_lock(&mutex);/*鎖住互斥量*/
- printf("thread1: lock %d/n", __LINE__);
- if(i%3==0){
- printf("thread1:signal 1 %d/n", __LINE__);
- pthread_cond_signal(&cond);/*條件改變,發送信號,通知t_b進程*/
- printf("thread1:signal 2 %d/n", __LINE__);
- sleep(1);
- }
- pthread_mutex_unlock(&mutex);/*解鎖互斥量*/
- printf("thread1: unlock %d/n/n", __LINE__);
- sleep(1);
- }
- }
- void *thread2(void *junk)
- {
- while(i<6)
- {
- pthread_mutex_lock(&mutex);
- printf("thread2: lock %d/n", __LINE__);
- if(i%3!=0){
- printf("thread2: wait 1 %d/n", __LINE__);
- pthread_cond_wait(&cond,&mutex);/*解鎖mutex,並等待cond改變*/
- printf("thread2: wait 2 %d/n", __LINE__);
- }
- pthread_mutex_unlock(&mutex);
- printf("thread2: unlock %d/n/n", __LINE__);
- sleep(1);
- }
- }
編譯:
[X61@horizon threads]$ gcc thread_cond.c -lpthread -o tcd
以下是程序運行結果:
[X61@horizon threads]$ ./tcd
thread1: lock 30
thread1: unlock 40
thread2: lock 52
thread2: wait 1 55
thread1: lock 30
thread1: unlock 40
thread1: lock 30
thread1:signal 1 33
thread1:signal 2 35
thread1: unlock 40
thread2: wait 2 57
thread2: unlock 61
thread1: lock 30
thread1: unlock 40
thread2: lock 52
thread2: wait 1 55
thread1: lock 30
thread1: unlock 40
thread1: lock 30
thread1:signal 1 33
thread1:signal 2 35
thread1: unlock 40
thread2: wait 2 57
thread2: unlock 61
這裏的兩個關鍵函數就在pthread_cond_wait和pthread_cond_signal函數。
本例中:
線程一先執行,獲得mutex鎖,打印,然後釋放mutex鎖,然後阻塞自己1秒。
線程二此時和線程一應該是併發的執行 ,這裏是一個要點,爲什麼說是線程此時是併發的執行,因爲此時不做任何干涉的話,是沒有辦法確定是線程一先獲得執行還是線程二先獲得執行,到底那個線程先獲得執行,取決於操作系統的調度,想刻意的讓線程2先執行,可以讓線程2一出來,先sleep一秒。
這裏併發執行的情況是,線程一先進入循環,然後獲得鎖,此時估計線程二執行,阻塞在
pthread_mutex_lock(&mutex);
這行語句中,直到線程1釋放mutex鎖
pthread_mutex_unlock(&mutex);/*解鎖互斥量*/
然後線程二得已執行,獲取metux鎖,滿足if條件,到pthread_cond_wait (&cond,&mutex);/*等待*/
這裏的線程二阻塞,不僅僅是等待cond變量發生改變,同時釋放mutex鎖 ,因爲當時看書沒有注意,所以這裏卡了很久。
mutex鎖釋放後,線程1終於獲得了mutex鎖,得已繼續運行,當線程1的if(i%3==0)的條件滿足後,通過pthread_cond_signal發送信號,告訴等待cond的變量的線程(這個情景中是線程二),cond條件變量已經發生了改變。
不過此時線程二並沒有立即得到運行 ,因爲線程二還在等待mutex鎖的釋放,所以線程一繼續往下走,直到線程一釋放mutex鎖,線程二才能停止等待,打印語句,然後往下走通過pthread_mutex_unlock(&mutex)釋放mutex鎖,進入下一個循環。