條件變數

一般過程

等待條件變數(生產者/消費者示例中的 queueCond)始終耦合到互斥鎖(生產者/消費者示例中的 queueMutex),並且應始終耦合到正常狀態變數(queue.empty( )在生產者/消費者的例子中)。如果使用正確,這可確保消費者不會錯過任何新資料。

一般來說,這個過程應該是:

  • 對於信令執行緒:
    1. 鎖定互斥鎖
    2. 更新任何資料和狀態變數
    3. 發出條件變數的訊號
    4. 解鎖互斥鎖
  • 對於等待執行緒:
    1. 鎖定互斥鎖
    2. 在狀態變數上執行 while 迴圈,只要資料沒有準備好就迴圈
    3. while 迴圈中,使用 pthread_cond_wait() 對條件變數進行等待
    4. while 迴圈退出時,我們現在確定新資料已準備就緒,並且互斥鎖被鎖定
    5. 對資料做點什麼
    6. 解鎖互斥鎖並重復

使用這種方案,無論何時排程信令和等待執行緒,等待執行緒都不會丟失資料(因為,它將永遠不會在有效資料就緒的情況下永遠等待)。這可以通過手動嘗試執行信令執行緒的步驟,為等待執行緒中的每個步驟記錄互斥體的狀態,條件和狀態變數來實現。

pthread_cond_wait 和互斥體

為了便於上述過程,需要在鎖定互斥鎖的情況下呼叫 pthread_cond_wait()。當呼叫時,pthread_cond_wait() 將線上程進入休眠狀態之前解鎖互斥鎖,並且在返回之前,無論出於何種原因,互斥鎖都將被重新鎖定。這也意味著如果某個其他執行緒當前鎖定了互斥鎖,pthread_cond_wait() 將等待互斥鎖被解鎖,直到等待執行緒實際上可以獲取互斥鎖 - 它將與其他任何試圖鎖定互斥鎖的執行緒一起攻擊它同時。

虛假的喚醒

此外,似乎等待狀態變數的 while 迴圈可以替換為簡單的 if 語句。然而,需要 while 迴圈,因為 Posix 標準允許 pthread_cond_wait() 在等待期間進行所謂的虛假喚醒,而不實際發出訊號。因此,程式碼需要重新檢查狀態變數以檢視 pthread_cond_wait() 是否由於實際發出訊號而返回,或者由於這些虛假喚醒之一而返回。