**linux中幫助中提到:**在多核處理器下,pthread_cond_signal可能會啟用多於乙個執行緒(阻塞在條件變數上的執行緒)。結果是,當乙個執行緒呼叫pthread_cond_signal()後,多個呼叫pthread_cond_wait()或pthread_cond_timedwait()的執行緒返回。這種效應成為」虛假喚醒。雖然虛假喚醒在pthread_cond_wait函式中可以解決,為了發生概率很低的情況而降低邊緣條件,效率是不值得的,糾正這個問題會降低對所有基於它的所有更高階的同步操作的併發度。所以pthread_cond_wait的實現上沒有去解決它。新增while檢查的做法被認為是增加了程式的健壯性,在ieee std 1003.1-2001中認為spurious wakeup是允許的。
所以通常的標準解決辦法是這樣的:
將條件的判斷從if 改為while,舉例子說明:
下面為執行緒處理函式:
如果不存在虛假喚醒的情況,那麼下面**:static void *thread_func(void *arg)
msg = msg_list.pop();
pthread_mutex_unlock(&mtx); //臨界區資料操作完畢,釋放互斥鎖
// handle msg
}return 0;
}
while (msg_list.empty())
可以為
if (msg_list.empty())
但是存在虛假喚醒的時候,如果用if,而不用while,那麼但被虛假喚醒的時候,不會再次while判斷,而是繼續下面執行msg = msg_list.pop();這其實是邏輯上有問題的。因為下面的**已經假定了msg_list不是空的。
舉例:
多核環境下,執行緒1、2都在thread_func函式中阻塞等待,某刻這兩個執行緒被pthread_cond_signal同時喚醒並競爭互斥鎖想要向下執行,執行緒1成功獲取鎖,並向下執行從訊息佇列取出訊息,此刻執行緒2仍因為獲取不到鎖而阻塞,執行緒1取完訊息後釋放鎖後,執行緒2繼續向下執行,但此時訊息佇列中已沒有資料,所以對於執行緒2來說,此次喚醒是虛假喚醒。需要在被喚醒後在次判斷條件是否成立來避免這種情況
注:呼叫pthread_cond_broadcast會喚醒所有等待執行緒,也會出現虛擬喚醒情況,同多核處理器的情況一樣,所以呼叫pthread_cond_broadcast的程式中也需要做虛擬喚醒處理
舉例:
執行結果:主線程呼叫pthread_cond_broadcast後,執行緒1比執行緒0先喚醒,執行緒1在pthread_cond_wait函式中成功加鎖,此時執行緒0雖喚醒但阻塞在pthread_cond_wait中的加鎖操作,執行緒1修改完flag值後釋放鎖,執行緒0拿到鎖繼續執行,但flag值已被執行緒1更改。所以這次喚醒對於執行緒0來說是虛假喚醒。#include #include #include #include #include #include #include #include #include pthread_cond_t cond = pthread_cond_initializer;
pthread_mutex_t mutex = pthread_mutex_initializer;
int flag = 1;
void *thread(void *arg)
pthread_mutex_unlock(&mutex);
} pthread_exit(0); }
int main()
參考:thread 1: wait
thread 0: wait
broadcast
thread 1:get cond, 1
thread 1: end
thread 0:get cond, 0
thread 0: end
條件變數之虛假喚醒
接下來,給出 pthread cond wait 和 pthread cond signal 的偽 參考man pthread cond signal 語句後面的編號代表時間上的執行順序。pthread cond wait mutex,cond else pthread mutex lock mut...
條件變數之虛假喚醒
如有錯誤請及時指正!3.如何避免虛假喚醒 當我們使用互斥量 mutex 與條件變數 condition variable 進行多執行緒同步時有可能會產生虛假喚醒現象,那麼究竟什麼是虛假喚醒,它會在什麼情況下被觸發,什麼情況下無需考慮虛假喚醒,如何避免?linux幫助中有提到 在多核處理器下,pthr...
深入理解條件變數 虛假喚醒
深入條件變數 pthread cond wait 和pthread cond signal 的偽實現 pthread cond wait mutex,cond 競爭失敗,那麼就不加入等待佇列了,相當於直接 喚醒 else pthread mutex unlock cond mutex 重新鎖住傳入的...