條件變數使用不當引起的虛假喚醒

2022-06-30 03:42:10 字數 1757 閱讀 4687

說到條件變數,首先說下互斥鎖,互斥鎖是最一種同步形式,用於保護臨界區,以保證任何時刻只有乙個執行緒在執行其中的**(假設互斥鎖由多個執行緒共享),來保證共享資料的完整性,上鎖過程如下圖;

假如在乙個程式中由3個執行緒訪問乙個共享變數g_count,其中執行緒1和執行緒是負責對g_count變數加一,執行緒3是負責對g_count變數減一;執行緒4是負責判斷g_count是否大於等於100,是就將變數g_count清零,**片段如下:

//執行緒1,2

while (1)

//執行緒3

while (1)

//執行緒3

while(1)

else

sleep(1);

}

上面這段**中的執行緒4並不知變數g_count什麼時候才會大於等於100,這就需要一直的迴圈判斷,但是每次的判斷都有上鎖和解鎖的操作(上鎖和操作是很費時的),這會帶來cpu資源浪費;對於這個問題可以使用條件變數處理;

條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作:乙個執行緒等待"條件變數的條件成立"而掛起;另乙個執行緒使"條件成立"(給出條件成立訊號);為了防止競爭,條件變數的使用總是和乙個互斥鎖結合在一起;

條件變數是由互斥鎖保護的,執行緒在改變條件狀態前必須先鎖住互斥鎖,其他執行緒在獲得互斥量之前不會察覺到這種改變,因為必須鎖定互斥鎖才能計算條件;

將之前的**使用條件變數修改:

//執行緒1,2

while (1)

sleep(1);

}//執行緒1,2

while (1)

//執行緒4

while(1)

g_count = 0;

pthread_mutex_unlock(&mutex);

sleep(1);

}

在《unix環境高階程式設計》中,有這麼一段:

;所以上面這段**中的執行緒3如果g_count小於100,執行緒3會呼叫pthread_cond_wait,而pthread_cond_wait會釋放mutex,然後等待條件變為真返回,pthread_cond_wait返回時會再次鎖住mutex;條件不滿足時pthread_cond_wait會等待,從而不用一直的輪詢,減少cpu的浪費;

至於上面的**中的使用while的原因,在多核處理器下,pthread_cond_signal可能會啟用多於乙個執行緒(阻塞在條件變數上的執行緒);結果就是,當乙個執行緒呼叫pthread_cond_signal()後,多個呼叫pthread_cond_wait()或pthread_cond_timedwait()的執行緒返回;這種效應就稱為「虛假喚醒」;

在pthread_cond_wait的man手冊中,對虛假喚醒有這樣一段話:

需要對條件進行再判斷以避免虛假喚醒:

如果用if判斷,多個等待執行緒在滿足if條件時都會被喚醒(虛假的),但實際上條件並不滿足,生產者生產出來的消費品已經被第乙個執行緒消費了;

這就是我們使用while去做判斷而不是使用if的原因:因為等待在條件變數上的執行緒被喚醒有可能不是因為條件滿足而是由於虛假喚醒;所以我們需要對條件變數的狀態進行不斷檢查直到其滿足條件,不僅要在pthread_cond_wait前檢查條件是否成立,在pthread_cond_wait之後也要檢查;

參考:

c thread 使用不當導致的崩潰問題

看個例子 1 class ctimer7 開始8void start 914 15void run 1622 23 結束24 void stop 2532 33 private 34 std thread t 35 std thread t1 36int i 37 bool b exit 38 39...

Select 使用不當引發的core,你應該知道的

排查乙個宕機問題,搞了好幾天時間,最終確定原因 最終確定問題原因,在此分享一下 如下rip不正確,指令位址錯亂,棧資訊已破壞 在此基礎上準確定位非常困難,但是仍可發現一些線索 根據當前棧資訊,大概尋找到懷疑的函式 檢視整個棧上下資訊,看有無懷疑的函式 所以很有可能就是fetchnsaddrev函式導...

Select 使用不當引發的core,你應該知道的

排查乙個宕機問題,搞了好幾天時間,最終確定原因 最終確定問題原因,在此分享一下 如下rip不正確,指令位址錯亂,棧資訊已破壞 在此基礎上準確定位非常困難,但是仍可發現一些線索 根據當前棧資訊,大概尋找到懷疑的函式 檢視整個棧上下資訊,看有無懷疑的函式 所以很有可能就是fetchnsaddrev函式導...