18.執行緒同步:條件變數cond
阿新 • • 發佈:2018-11-12
1.條件變數
1.條件變數(Condtion Variable)是在多執行緒程式中用來實現“等待->喚醒”邏輯常用的方法。
2.條件變數+互斥鎖(一起使用)
執行緒同步——互斥鎖
阻塞執行緒——條件變數
2.條件變數使用場景舉例
舉個簡單的例子,應用程式A中包含兩個執行緒t1和t2。t1需要在 bool變數test_cond為true時 才能繼續執行,而test_cond的值是由t2來改變的,這種情況下,如何來寫程式呢?可供選 擇的方案有兩 種: 第一種是t1定時的去輪詢變數test_cond,如果test_cond為false,則繼續休眠;如果test_cond為 true,則開始執行。 第二種就是上面提到的條件變數,t1在test_cond為false時呼叫cond_wait進行等待,t2在改變 test_cond的值後,呼叫cond_signal,喚醒在等待中的t1,告訴t1 test_cond的值變了,這樣t1便可 繼續往下執行。 [效能對比分析] 很明顯,上面兩種方案中,第二種方案是比較優的。在第一種方案中,在每次輪詢時,如果t1休 眠的時間比較短,會導致cpu浪費很厲害;如果t1休眠的時間 比較長,又會導致應用邏輯處理不夠 及時,致使應用程式效能下降。第二種方案就是為了解決輪詢的弊端而生的。
3.相關函式
pthread_cond_t cond; //條件變數型別 int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); //初始化 int pthread_cond_destroy(pthread_cond_t *cond); //銷燬 //當條件不到來時,僅僅只阻塞一定的時長 int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); //當條件不到來時,一直阻塞 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); //喚醒[至少一個]阻塞在條件變數上等待的執行緒 int pthread_cond_signal(pthread_cond_t *cond); //廣播:喚醒[全部]的阻塞在條件變數上等待的執行緒 int pthread_cond_broadcast(pthread_cond_t *cond);
註解:pthread_cond_wait 函式剖析
pthread_cond_wait的內部執行原理: [1]先對mutex解鎖,解鎖後再阻塞,一直等待條件到來; //條件沒到來時,程式阻塞在pthread_cond_wait處 [2]當條件到來(被pthread_cond_signal喚醒)時,解除阻塞,與此同時, pthread_cond_wait再對mutex加鎖;之後執行條件滿足的操作 問題:pthread_cond_wait為什麼要對mutex解鎖? (1)使得其他執行緒有機會進入臨界區,等待相同的條件 (2)使得其他執行緒有機會進入臨界區,對臨界資源進行更改
4.使用條件變數的萬能公式
執行緒A(等待條件的執行緒)
pthread_mutex_lock(mutex)
while(條件不滿足){
pthread_cond_wait(&cond);
}
執行條件滿足的操作
pthread_mutex_unlock(mutex)
----------------------------------------
執行緒B(修改條件的執行緒)
pthread_mutex_lock(mutex)
修改條件
pthread_mutex_unlock(&mutex);
if(條件滿足){
pthread_cond_signal(&cond)
}
疑問:為什麼等待條件的執行緒的程式碼中使用while,而不是if
防止被虛假的喚醒,當是虛假的喚醒操作時,由於使用的while,因此需要再判斷一次,
條件不滿足時,繼續阻塞。