條件變量 pthread_cond_t

Linux操作系統下的多線程編程詳細解析----條件變量

 

1.初始化條件變量pthread_cond_init

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *cv,

const pthread_condattr_t *cattr);

返回值:函數成功返回0;任何其他返回值都表示錯誤

初始化一個條件變量。當參數cattr爲空指針時,函數創建的是一個缺省的條件變量。否則條件變量的屬性將由cattr中的屬性值來決定。調用 pthread_cond_init函數時,參數cattr爲空指針等價於cattr中的屬性爲缺省屬性,只是前者不需要cattr所佔用的內存開銷。這個函數返回時,條件變量被存放在參數cv指向的內存中。

可以用宏PTHREAD_COND_INITIALIZER來初始化靜態定義的條件變量,使其具有缺省屬性。這和用pthread_cond_init函數動態分配的效果是一樣的。初始化時不進行錯誤檢查。如:

pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

不能由多個線程同時初始化一個條件變量。當需要重新初始化或釋放一個條件變量時,應用程序必須保證這個條件變量未被使用。

 

2.阻塞在條件變量上pthread_cond_wait

#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *cv,

pthread_mutex_t *mutex);

返回值:函數成功返回0;任何其他返回值都表示錯誤

函數將解鎖mutex參數指向的互斥鎖,並使當前線程阻塞在cv參數指向的條件變量上。

被阻塞的線程可以被pthread_cond_signal函數,pthread_cond_broadcast函數喚醒,也可能在被信號中斷後被喚醒。

pthread_cond_wait函數的返回並不意味着條件的值一定發生了變化,必須重新檢查條件的值。

pthread_cond_wait函數返回時,相應的互斥鎖將被當前線程鎖定,即使是函數出錯返回。

一般一個條件表達式都是在一個互斥鎖的保護下被檢查。當條件表達式未被滿足時,線程將仍然阻塞在這個條件變量上。當另一個線程改變了條件的值並向條件變量發出信號時,等待在這個條件變量上的一個線程或所有線程被喚醒,接着都試圖再次佔有相應的互斥鎖。

阻塞在條件變量上的線程被喚醒以後,直到pthread_cond_wait()函數返回之前條件的值都有可能發生變化。所以函數返回以後,在鎖定相應的互斥鎖之前,必須重新測試條件值。最好的測試方法是循環調用pthread_cond_wait函數,並把滿足條件的表達式置爲循環的終止條件。如:

pthread_mutex_lock();

while (condition_is_false)

pthread_cond_wait();

pthread_mutex_unlock();

阻塞在同一個條件變量上的不同線程被釋放的次序是不一定的。

注意:pthread_cond_wait()函數是退出點,如果在調用這個函數時,已有一個掛起的退出請求,且線程允許退出,這個線程將被終止並開始執行善後處理函數,而這時和條件變量相關的互斥鎖仍將處在鎖定狀態。

 

3.解除在條件變量上的阻塞pthread_cond_signal

#include <pthread.h>

int pthread_cond_signal(pthread_cond_t *cv);

返回值:函數成功返回0;任何其他返回值都表示錯誤

函數被用來釋放被阻塞在指定條件變量上的一個線程。

必須在互斥鎖的保護下使用相應的條件變量。否則對條件變量的解鎖有可能發生在鎖定條件變量之前,從而造成死鎖。

喚醒阻塞在條件變量上的所有線程的順序由調度策略決定,如果線程的調度策略是SCHED_OTHER類型的,系統將根據線程的優先級喚醒線程。

如果沒有線程被阻塞在條件變量上,那麼調用pthread_cond_signal()將沒有作用。

 

4.阻塞直到指定時間pthread_cond_timedwait

#include <pthread.h>

#include <time.h>

int pthread_cond_timedwait(pthread_cond_t *cv,

pthread_mutex_t *mp, const structtimespec * abstime);

返回值:函數成功返回0;任何其他返回值都表示錯誤

函數到了一定的時間,即使條件未發生也會解除阻塞。這個時間由參數abstime指定。函數返回時,相應的互斥鎖往往是鎖定的,即使是函數出錯返回。

注意:pthread_cond_timedwait函數也是退出點。

超時時間參數是指一天中的某個時刻。使用舉例:

pthread_timestruc_t to;

to.tv_sec = time(NULL) + TIMEOUT;

to.tv_nsec = 0;

超時返回的錯誤碼是ETIMEDOUT。

 

5.釋放阻塞的所有線程pthread_cond_broadcast

#include <pthread.h>

int pthread_cond_broadcast(pthread_cond_t *cv);

返回值:函數成功返回0;任何其他返回值都表示錯誤

函數喚醒所有被pthread_cond_wait函數阻塞在某個條件變量上的線程,參數cv被用來指定這個條件變量。當沒有線程阻塞在這個條件變量上時,pthread_cond_broadcast函數無效。

由於pthread_cond_broadcast函數喚醒所有阻塞在某個條件變量上的線程,這些線程被喚醒後將再次競爭相應的互斥鎖,所以必須小心使用pthread_cond_broadcast函數。

 

6.釋放條件變量pthread_cond_destroy

#include <pthread.h>

int pthread_cond_destroy(pthread_cond_t *cv);

返回值:函數成功返回0;任何其他返回值都表示錯誤

釋放條件變量。

注意:條件變量佔用的空間並未被釋放。

 

7.喚醒丟失問題

在線程未獲得相應的互斥鎖時調用pthread_cond_signal或pthread_cond_broadcast函數可能會引起喚醒丟失問題。

喚醒丟失往往會在下面的情況下發生:

  1. 一個線程調用pthread_cond_signal或pthread_cond_broadcast函數;
  2. 另一個線程正處在測試條件變量和調用pthread_cond_wait函數之間;
  3. 沒有線程正在處在阻塞等待的狀態下。

 

轉載聲明: 本文轉自 http://pzs1237.blog.163.com/blog/static/29813006200952335454934/

 

===============================================================================

 

條件鎖pthread_cond_t

 

說明,
等待線程
1。使用pthread_cond_wait前要先加鎖
2。pthread_cond_wait內部會解鎖,然後等待條件變量被其它線程激活
3。pthread_cond_wait被激活後會再自動加鎖

激活線程:
1。加鎖(和等待線程用同一個鎖)
2。pthread_cond_signal發送信號
3。解鎖
激活線程的上面三個操作在運行時間上都在等待線程的pthread_cond_wait函數內部。

程序示例:

  1. #include <stdio.h>   
  2. #include <pthread.h>   
  3. #include <unistd.h>   
  4.   
  5. pthread_mutex_t count_lock;  
  6. pthread_cond_t count_nonzero;  
  7. unsigned count = 0;  
  8.   
  9. void *decrement_count(void *arg)  
  10. {  
  11.     pthread_mutex_lock(&count_lock);  
  12.     printf("decrement_count get count_lock/n");  
  13.     while(count == 0)  
  14.     {  
  15.         printf("decrement_count count == 0 /n");  
  16.         printf("decrement_count before cond_wait /n");  
  17.         pthread_cond_wait(&count_nonzero, &count_lock);  
  18.         printf("decrement_count after cond_wait /n");  
  19.     }  
  20.   
  21.     count = count + 1;  
  22.     pthread_mutex_unlock(&count_lock);  
  23. }  
  24.   
  25. void *increment_count(void *arg)  
  26. {  
  27.     pthread_mutex_lock(&count_lock);  
  28.     printf("increment_count get count_lock /n");  
  29.     if(count == 0)  
  30.     {  
  31.         printf("increment_count before cond_signal /n");  
  32.         pthread_cond_signal(&count_nonzero);  
  33.         printf("increment_count after cond_signal /n");  
  34.     }  
  35.   
  36.     count = count + 1;  
  37.     pthread_mutex_unlock(&count_lock);  
  38. }  
  39.   
  40. int main(void)  
  41. {  
  42.     pthread_t tid1, tid2;  
  43.   
  44.     pthread_mutex_init(&count_lock, NULL);  
  45.     pthread_cond_init(&count_nonzero, NULL);  
  46.   
  47.     pthread_create(&tid1, NULL, decrement_count, NULL);  
  48.     sleep(2);  
  49.     pthread_create(&tid2, NULL, increment_count, NULL);  
  50.   
  51.     sleep(10);  
  52.     pthread_exit(0);  
  53.   
  54.     return 0;  
  55. }  


運行結果:

[[email protected] pthread]$ gcc -o pthread_cond pthread_cond.c -lpthread
[[email protected] pthread]$ ./pthread_cond
decrement_count get count_lock
decrement_count count == 0
decrement_count before cond_wait
increment_count get count_lock
increment_count before cond_signal
increment_count after cond_signal
decrement_count after cond_wait

 

轉載聲明: 本文轉自 http://egeho123.blogbus.com/logs/10821816.html

 

===============================================================================

 

多線程編程,條件變量pthread_cond_t應用

 

程序代碼:

 

  1. #include <stdio.h>   
  2. #include <pthread.h>   
  3. #include <unistd.h>   
  4.   
  5. pthread_mutex_t counter_lock;  
  6. pthread_cond_t counter_nonzero;  
  7. int counter = 0;  
  8. int estatus = -1;  
  9.   
  10. void *decrement_counter(void *argv);  
  11. void *increment_counter(void *argv);  
  12.   
  13. int main(int argc, char **argv)  
  14. {  
  15.     printf("counter: %d/n", counter);  
  16.     pthread_t thd1, thd2;  
  17.     int ret;  
  18.   
  19.     ret = pthread_create(&thd1, NULL, decrement_counter, NULL);  
  20.     if(ret){  
  21.         perror("del:/n");  
  22.         return 1;  
  23.     }  
  24.   
  25.     ret = pthread_create(&thd2, NULL, increment_counter, NULL);  
  26.     if(ret){  
  27.         perror("inc: /n");  
  28.         return 1;  
  29.     }  
  30.   
  31.     int counter = 0;  
  32.     while(counter != 10){  
  33.         printf("counter: %d/n", counter);  
  34.         sleep(1);  
  35.         counter++;  
  36.     }  
  37.   
  38.     return 0;  
  39. }  
  40.   
  41. void *decrement_counter(void *argv)  
  42. {  
  43.     pthread_mutex_lock(&counter_lock);  
  44.     while(counter == 0)  
  45.         pthread_cond_wait(&counter_nonzero, &counter_lock);  
  46.   
  47.     counter--;  
  48.     pthread_mutex_unlock(&counter_lock);  
  49.   
  50.     return &estatus;  
  51. }  
  52.   
  53. void *increment_counter(void *argv)  
  54. {  
  55.     pthread_mutex_lock(&counter_lock);  
  56.     if(counter == 0)  
  57.         pthread_cond_signal(&counter_nonzero);  
  58.   
  59.     counter++;  
  60.     pthread_mutex_unlock(&counter_lock);  
  61.   
  62.     return &estatus;  
  63. }  

 

運行結果:
[[email protected] pthread]$ gcc -o pthread_cond2 pthread_cond2.c -lpthread
[[email protected] pthread]$ ./pthread_cond2                              
counter: 0
counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9

 

調試程序的運行過程:

1、開始時 counter 爲0 (main)
2、ret = pthread_create(&thrd1, NULL, decrement_counter, NULL)處生成一個thrd1線程運行decrement_counter(),
此線程內函數運行流程爲:
先鎖定 互斥鎖(count_lock) 如果counter爲0,此線程被阻塞在條件變量(count_nonzero)上.同時釋放互斥鎖count_lock(wait內部會先釋放鎖,等待signal激活後自動再加上鎖).

 

3、與此同時主程序還在運行,創建另一個線程thrd2運行 increment_counter,
此線程內的函數流程如下:
先鎖定 互斥鎖(count_lock)【wait內部釋放鎖的互斥鎖】 如果counter爲0, 喚醒在條件變量(count_nonzero)上的線程即thrd1.但是由於有互斥鎖count_lock【signal激活後,wait內部又自動加上鎖了】, thrd1還是在等待. 然後count++,釋放互斥鎖,.......thrd1由於互斥鎖釋放,重新判斷counter是不是爲0,如果爲0再把線程阻塞在條件變量count_nonzero上,但這時counter已經爲1了.所以線程繼續運行.counter--釋放互斥鎖......(退出後,運行主線程main
4、與此主程序間隔打印counter運行一段時間退出.

 注:更清晰的運行流程請詳見如下“改進代碼”

後記,在編譯的時候加上 -lpthread
改進代碼:

  1. #include <stdio.h>   
  2. #include <pthread.h>   
  3. #include <unistd.h>   
  4.   
  5. pthread_mutex_t counter_lock;  
  6. pthread_cond_t counter_nonzero;  
  7. int counter = 0;  
  8. int estatus = -1;  
  9.   
  10. void *decrement_counter(void *argv);  
  11. void *increment_counter(void *argv);  
  12.   
  13. int main(int argc, char **argv)  
  14. {  
  15.     printf("counter: %d/n", counter);  
  16.     pthread_t thd1, thd2;  
  17.     int ret;  
  18.   
  19.     ret = pthread_create(&thd1, NULL, decrement_counter, NULL);  
  20.     if(ret){  
  21.         perror("del:/n");  
  22.         return 1;  
  23.     }  
  24.   
  25.     ret = pthread_create(&thd2, NULL, increment_counter, NULL);  
  26.     if(ret){  
  27.         perror("inc: /n");  
  28.         return 1;  
  29.     }  
  30.   
  31.     int counter = 0;  
  32.     while(counter != 10){  
  33.         printf("counter(main): %d/n", counter);  
  34.         sleep(1);  
  35.         counter++;  
  36.     }  
  37.   
  38.     return 0;  
  39. }  
  40.   
  41. void *decrement_counter(void *argv)  
  42. {  
  43.     printf("counter(decrement): %d/n", counter);  
  44.     pthread_mutex_lock(&counter_lock);  
  45.     while(counter == 0)  
  46.         pthread_cond_wait(&counter_nonzero, &counter_lock); //進入阻塞(wait),等待激活(signal)   
  47.       
  48.     printf("counter--(before): %d/n", counter);      
  49.     counter--; //等待signal激活後再執行   
  50.     printf("counter--(after): %d/n", counter);      
  51.     pthread_mutex_unlock(&counter_lock);   
  52.   
  53.     return &estatus;  
  54. }  
  55.   
  56. void *increment_counter(void *argv)  
  57. {  
  58.     printf("counter(increment): %d/n", counter);  
  59.     pthread_mutex_lock(&counter_lock);  
  60.     if(counter == 0)  
  61.         pthread_cond_signal(&counter_nonzero); //激活(signal)阻塞(wait)的線程(先執行完signal線程,然後再執行wait線程)   
  62.   
  63.     printf("counter++(before): %d/n", counter);      
  64.     counter++;   
  65.     printf("counter++(after): %d/n", counter);      
  66.     pthread_mutex_unlock(&counter_lock);  
  67.   
  68.     return &estatus;  
  69. }  

運行結果:
[[email protected] pthread]$ gcc -o pthread_cond2 pthread_cond2.c -lpthread
[[email protected] pthread]$ ./pthread_cond2                              
counter: 0
counter(main): 0
counter(decrement): 0
counter(increment): 0
counter++(before): 0
counter++(after): 1
counter--(before): 1
counter--(after): 0
counter(main): 1
counter(main): 2
counter(main): 3
counter(main): 4
counter(main): 5
counter(main): 6
counter(main): 7
counter(main): 8
counter(main): 9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章