日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pthread_cond_wait的spurious wakeup问题

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pthread_cond_wait的spurious wakeup问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在溫習pthread的時候,忽然發現以前對pthread_cond_wait的了解太膚淺了。昨晚在看《Programming With POSIX Threads》的時候,看到了pthread_cond_wait的通常使用方法:

pthread_mutex_lock();

while(condition_is_false)

??? pthread_cond_wait();

pthread_mutex_unlock();

為什么在pthread_cond_wait()前要加一個while循環來判斷條件是否為假呢?

APUE中寫道:

傳遞給pthread_cond_wait的互斥量對條件進行保護,調用者把鎖住的互斥量傳給函數。函數把調用線程放到等待條件的線程列表上,然后對互斥量解鎖,這兩個操作是原子操作。

線程釋放互斥量,等待其他線程發給該條件變量的信號(喚醒一個等待者)或廣播該條件變量(喚醒所有等待者)。當等待條件變量時,互斥量必須始終為釋放的,這樣其他線程才有機會鎖住互斥量,修改條件變量。當線程從條件變量等待中醒來時,它重新繼續鎖住互斥量,對臨界資源進行處理。

條件變量的作用是發信號,而不是互斥。

wait前檢查

對于多線程程序,不能夠用常規串行的思路來思考它們,因為它們是完全異步的,會出現很多臨界情況。比如:pthread_cond_signal的時間早于pthread_cond_wait的時間,這樣pthread_cond_wait就會一直等下去,漏掉了之前的條件變化。

對于這種情況,解決的方法是在鎖住互斥量之后和等待條件變量之前,檢查條件變量是否已經發生變化。

if(condition_is_false)

??? pthread_cond_wait();

這樣在等待條件變量前檢查一下條件變量的值,如果條件變量已經發生了變化,那么就沒有必要進行等待了,可以直接進行處理。這種方法在并發系統中比較常見,例如之前PACKET_MMAP中poll的競爭條件的解決方法。

-----------------------------------------------------------------------

忽然想起了設計模式中的單件模式的"雙重檢查加鎖":

Singleton *getInstance()

{

??? if(ptr==NULL)

??? {

??????? LOCK();

??????? if(ptr==NULL)

??????? {

??????????? ptr = new Singleton();

??????? }

??????? UNLOCK();

??? }

??? return ptr;

}

這樣只有在第一次的時候會進行鎖(應該是第一輪,如果剛開始有多個線程進入了最上層的ptr==NULL代碼塊,就會有多次鎖,只不過之后就不會鎖了),之后就不會鎖了。

pthread_once()的實現也是基于單件模式的。

pthread_once函數首先檢查控制變量,以判斷是否已經完成初始化。如果完成,pthread_once簡單的返回;否則,pthread_once調用初始化函數(沒有參數),并記錄下初始化被完成。如果在一個線程初始化時,另外的線程調用pthread_once,則調用線程將等待,直到那個線程完成初始化后返回。換句話,當調用pthread_once成功返回時,調用者能夠肯定所有的狀態已經初始化完畢。

int

__pthread_once (once_control, init_routine)

???? pthread_once_t *once_control;

???? void (*init_routine) (void);

{

? /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a

???? global lock variable or one which is part of the pthread_once_t

???? object.? */

? if (*once_control == PTHREAD_ONCE_INIT)

??? {

????? lll_lock (once_lock, LLL_PRIVATE);

????? /* XXX This implementation is not complete.? It doesn't take

cancelation and fork into account.? */

????? if (*once_control == PTHREAD_ONCE_INIT)

{

? init_routine ();

? *once_control = !PTHREAD_ONCE_INIT;

}

????? lll_unlock (once_lock, LLL_PRIVATE);

??? }

? return 0;

}

-----------------------------------------------------------------------

pthread_cond_wait中的while()不僅僅在等待條件變量前檢查條件變量,實際上在等待條件變量后也檢查條件變量。pthread_cond_wait返回后,還需要檢查條件變量,這是為什么呢?難道pthread_cond_wait不是pthread_cond_signal觸發了某個condition導致的嗎?

這個地方有些迷惑人,實際上pthread_cond_wait的返回不僅僅是pthread_cond_signal和pthread_cond_broadcast導致的,還會有一些假喚醒,也就是spurious wakeup。

何為假喚醒?顧名思義就是虛假的喚醒,與pthread_cond_signal和pthread_cond_broadcast的喚醒相對。那么什么情況下會導致假喚醒呢?可以閱讀參考1。

signal

大致意思是:

在linux中,pthread_cond_wait底層是futex系統調用。在linux中,任何慢速的阻塞的系統調用當接收到信號的時候,就會返回-1,并且設置errno為EINTR。在系統調用返回前,用戶程序注冊的信號處理函數會被調用處理。


注:什么有樣的系統調用會出現接收信號后發揮EINTR呢?

慢速阻塞的系統調用,有可能會永遠阻塞下去的那種。當接收到信號的時候,認為是一個返回并執行其他代碼的一個時機。

信號的處理也不簡單,因為有些慢系統調用被信號中斷后是會自動重啟的,所以我們通常需要用siginterrupt(signo, 1)來關閉重啟或者在用sigaction安裝信號處理函數的時候取消SA_RESTART標志,之后就可以通過判斷信號的返回值是否是-1和errno是否為EINTR來判斷是否有信號抵達。

如果關閉了SA_RESTART的一些使用慢速系統調用的應用,一般都采用while()循環,檢測到EINTR后就重新調用。

while(1)

{

?? int ret = syscall();

?? if(ret<0 && errno==EINTR)

?????? continue;

?? else

?????? break;

}

但是,對于futex這種方法不行,因為futex結束后,再重新運行的過程中,會出現一個時間窗口,其他線程可能會在這個時間窗口中進行pthread_cond_signal,這樣,再進行pthread_cond_wait的時候就丟失了一次條件變量的變化。解決方法就是在pthread_cond_wait前檢查條件變量,也就是

pthread_mutex_lock();

while(condition_is_false)

??? pthread_cond_wait();

pthread_mutex_unlock();

pthread_cond_broadcast

實際上,不僅僅信號會導致假喚醒,pthread_cond_broadcast也會導致假喚醒。加入條件變量上有多個線程在等待,pthread_cond_broadcast會喚醒所有的等待線程,而pthread_cond_signal只會喚醒其中一個等待線程。這樣,pthread_cond_broadcast的情況也許要在pthread_cond_wait前使用while循環來檢查條件變量。

參考:

http://vladimir_prus.blogspot.com/2005/07/spurious-wakeups.html

http://www.lambdacs.com/cpt/FAQ.html#Q94

http://groups.google.de/group/comp.programming.threads/msg/bb8299804652fdd7

http://www.win.tue.nl/~aeb/linux/lk/lk-4.html#ss4.5

http://blog.chinaunix.net/u/5251/showart_309061.html

總結

以上是生活随笔為你收集整理的pthread_cond_wait的spurious wakeup问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。