在多線程同步互斥的應用場景下,通常會用到pthread_cond_wait()和pthread_cond_signal()函數。那麼這兩個函數到底是如何保證互斥同步的呢?
為了對上面的問題有個直覺的了解,可以從下面的問題着手。下面兩段這些程式有什麼bug麼?
a. 等待條件的線程執行的代碼:
Thread 1:
{
……………………..
pthread_cond_wait(cv, mutex);
do_worker_task();
}
b.喚醒等待線程的代碼:
pthread_mutex_lock(mutx);
pthread_cond_signal(cv)
pthread_mutex_unlock(mutex);
要知道上面代碼問題在哪,關鍵是必須對pthread_cond_wait()有深入的了解。為了對這個函數又直覺的了解,下面給出了pthread_cond_wait(cv, mutex)正常執行過程中的幾個重要子步驟僞碼:
pthread_cond_wait(cv, mutex) 實際做的事情:
a. pthread_mutex_unlock(mutex);
b. do_real_cond_wait(cv); // 可能在這阻塞直到其他線程調用pthread_cond_signal(cv)或者 pthread_cond_broadcast(cv),才會往下執行
c. pthread_mutex_lock(mutex);
結合在多處理器、多線程、高并發的環境下,上面三個步驟就顯得缺一不可,才能保證盡可能地互斥:
步驟a:保證其他線程此後也有等待、申請條件變量的同等機會
步驟b:在條件變量還沒就緒的情況下,執行真正的阻塞
步驟c:目前線程得到條件變量之後,阻止其他等待條件變量的線程繼續往下執行,而自己可以往下執行。
那麼問題來了,考慮步驟c,如果單獨一句pthread_cond_wait(cv, mutex)是無法確定線程盡可能互斥的,這就是為何在執行pthread_cond_wait()之前要求有pthread_mutex_lock(mutx)的原因了,是以正常申請條件變量的線程的流程應該如下:
至于釋放條件變量,了解了上邊的内部機制之後,其實在釋放條件變量之前就不需要申請鎖再釋放鎖了。
這裡要特别提到的一點是,按照上面正确申請條件變量的的流程,仍然存在多個等待條件變量的線程同時執行步驟b出等待,此時如果有信号釋放,就會喚醒多個線程。這也就是為什麼手冊上說pthread_cond_signal(cv)至少喚醒一個在等待cv的線程(可以計數資源為1)的原因了。
參考文檔和手冊:
man pthread_cond_signal
本文轉自存儲之廚51CTO部落格,原文連結:http://blog.51cto.com/xiamachao/1952614 ,如需轉載請自行聯系原作者