在多執行緒程式設計中,pthread_cond_wait 與 pthread_cond_signal 是常見的同步原語。然而,許多開發者在實際使用時會遇到「虛假喚醒」與「訊號遺漏」兩大經典問題。本文依據 IEEE Std 1003.1-2004 標準,深入剖析這兩個問題的成因,並給出正確的程式設計模式。
標準明確指出:在多處理器系統上,pthread_cond_signal 可能喚醒多個正在等待同一條件變量的執行緒。這意味著 pthread_cond_wait 返回時,條件未必已滿足。因此,必須使用 while 迴圈 重新檢查條件:
pthread_mutex_lock(&lock);
while (condition_is_false) {
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
標準不僅允許虛假喚醒,更鼓勵開發者在喚醒後重新評估條件,只有條件真正滿足時才繼續執行。
成因在於多核處理器的快取一致性機制:多執行緒共享資料需在各核心快取間更新、拷貝,導致訊號傳遞時可能觸發多個等待者。
pthread_cond_wait 內部將解鎖與進入阻塞合併為原子操作,確保在 pthread_cond_wait 之後發出的 pthread_cond_signal 不會丟失。但若 pthread_cond_signal 發生在 pthread_cond_wait 進入阻塞 之前,該訊號將永久遺漏,導致執行緒永久阻塞。
解決方案:引入一個計數器 count,在呼叫 pthread_cond_wait 前先檢查:
if (!count) {
pthread_mutex_lock(&lock);
while (condition_is_false) {
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
}
若 count != 0 表示已錯過訊號,可直接繼續執行而無需等待。
while 迴圈檢查條件,防範虛假喚醒。掌握這兩大核心問題,才能編寫健壯、高效的多執行緒程式。