條件變數
一般過程
等待條件變數(生產者/消費者示例中的 queueCond)始終耦合到互斥鎖(生產者/消費者示例中的 queueMutex),並且應始終耦合到正常狀態變數(queue.empty( )在生產者/消費者的例子中)。如果使用正確,這可確保消費者不會錯過任何新資料。
一般來說,這個過程應該是:
- 對於信令執行緒:
- 鎖定互斥鎖
- 更新任何資料和狀態變數
- 發出條件變數的訊號
- 解鎖互斥鎖
- 對於等待執行緒:
- 鎖定互斥鎖
- 在狀態變數上執行
while
迴圈,只要資料沒有準備好就迴圈 - 在
while
迴圈中,使用pthread_cond_wait()
對條件變數進行等待 - 當
while
迴圈退出時,我們現在確定新資料已準備就緒,並且互斥鎖被鎖定 - 對資料做點什麼
- 解鎖互斥鎖並重復
使用這種方案,無論何時排程信令和等待執行緒,等待執行緒都不會丟失資料(因為,它將永遠不會在有效資料就緒的情況下永遠等待)。這可以通過手動嘗試執行信令執行緒的步驟,為等待執行緒中的每個步驟記錄互斥體的狀態,條件和狀態變數來實現。
pthread_cond_wait
和互斥體
為了便於上述過程,需要在鎖定互斥鎖的情況下呼叫 pthread_cond_wait()
。當呼叫時,pthread_cond_wait()
將線上程進入休眠狀態之前解鎖互斥鎖,並且在返回之前,無論出於何種原因,互斥鎖都將被重新鎖定。這也意味著如果某個其他執行緒當前鎖定了互斥鎖,pthread_cond_wait()
將等待互斥鎖被解鎖,直到等待執行緒實際上可以獲取互斥鎖 - 它將與其他任何試圖鎖定互斥鎖的執行緒一起攻擊它同時。
虛假的喚醒
此外,似乎等待狀態變數的 while
迴圈可以替換為簡單的 if
語句。然而,需要 while
迴圈,因為 Posix 標準允許 pthread_cond_wait()
在等待期間進行所謂的虛假喚醒,而不實際發出訊號。因此,程式碼需要重新檢查狀態變數以檢視 pthread_cond_wait()
是否由於實際發出訊號而返回,或者由於這些虛假喚醒之一而返回。