用條件變量實現事件等待器的正確與錯誤作法 提到了8種 基於 linux pthread 條件變量實現的 Waiter classes,並分析了幾種錯誤實現的錯誤之處。本文進一步分析一下幾種正確實現的程序行爲,加深對Linux pthread 條件變量的理解。html
下面給出一個能夠用於single waiter的WaiterClass的正確實現。linux
class Waiter : private WaiterBase { public: void wait() { CHECK_SUCCESS(pthread_mutex_lock(&mutex_)); while (!signaled_) { CHECK_SUCCESS(pthread_cond_wait(&cond_, &mutex_)); } CHECK_SUCCESS(pthread_mutex_unlock(&mutex_)); } void signal() { CHECK_SUCCESS(pthread_mutex_lock(&mutex_)); // 0 signaled_ = true; // 1 CHECK_SUCCESS(pthread_mutex_unlock(&mutex_)); // 2 CHECK_SUCCESS(pthread_cond_signal(&cond_)); // 3 } private: bool signaled_ = false; };
要實現一個正確的Waiter Class, 由 1 可知 wait() 函數的指令順序必須如上所示。但signal() 函數能夠有幾種不一樣的實現,即代碼行 1,2,3能夠有幾種不一樣的順序組合,使得Waiter Class是正確的。這幾種組合包括了1 給出的幾種正確實現。函數
首先對 代碼行1,2,3 給出全部可能的排列形式,而後一一說明其是否正確。
a. 1-2-3
b. 1-3-2
c. 2-1-3
d. 2-3-1
e. 3-1-2
f. 3-2-1測試
要分析以上6種實現的對錯,先要了解一下 pthread_cond_wait 和 pthread_cond_signal 的內部流程。線程
假設等待信號的線程爲A,發出信號的線程爲B。code
線程A,pthread_cond_wait()內部包括如下流程:htm
線程B,pthread_cond_signal()包括如下流程:blog
signal 將一直喚醒G1組的 waiters 直到 G1 全部的 waiters 都被喚醒。若此過程種有新到達的waiter, 則存入G2 組(以後到達的 waiter 也存入G2)。G2組會在下次signal 調用時轉爲G1組,所以signal永遠只喚醒G1 組的 waiters。(參考)隊列
有了以上的細節,能夠很容易的得出問題的結論。事件
總結髮現,只要布爾值的修改是在釋放鎖的操做以前,就能保證其正確性。