一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

pthread_cond_wait的spurious wakeup問題 - 城市守望者 - 博客園

 techres 2010-12-15

http://www./u/12592/showart_2213910.html

最近在溫習pthread的時候,忽然發(fā)現(xiàn)以前對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循環(huán)來判斷條件是否為假呢?

APUE中寫道:

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

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

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

wait前檢查

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

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

if(condition_is_false)

    pthread_cond_wait();

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

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

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

Singleton *getInstance()

{

    if(ptr==NULL)

    {

        LOCK();

        if(ptr==NULL)

        {

            ptr = new Singleton();

        }

        UNLOCK();

    }

    return ptr;

}

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

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

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

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觸發(fā)了某個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系統(tǒng)調(diào)用。在linux中,任何慢速的阻塞的系統(tǒng)調(diào)用當接收到信號的時候,就會返回-1,并且設(shè)置errno為EINTR。在系統(tǒng)調(diào)用返回前,用戶程序注冊的信號處理函數(shù)會被調(diào)用處理。


注:什么有樣的系統(tǒng)調(diào)用會出現(xiàn)接收信號后發(fā)揮EINTR呢?

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

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

如果關(guān)閉了SA_RESTART的一些使用慢速系統(tǒng)調(diào)用的應用,一般都采用while()循環(huán),檢測到EINTR后就重新調(diào)用。

while(1)

{

   int ret = syscall();

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

       continue;

   else

       break;

}

但 是,對于futex這種方法不行,因為futex結(jié)束后,再重新運行的過程中,會出現(xiàn)一個時間窗口,其他線程可能會在這個時間窗口中進行 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循環(huán)來檢查條件變量。

參考:

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

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

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

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

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

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产av熟女一区二区三区蜜桃| 老司机精品福利视频在线播放| 国产一区二区三区精品免费| 亚洲一区二区三区精选| 欧美小黄片在线一级观看 | 久热这里只有精品九九| 精品日韩视频在线观看| 东京热加勒比一区二区| 免费黄片视频美女一区| 好吊妞在线免费观看视频| 丰满少妇被猛烈撞击在线视频| 粉嫩内射av一区二区| 欧美人妻少妇精品久久性色| 婷婷九月在线中文字幕| 国产精品一区二区三区日韩av | 国产一区麻豆水好多高潮| 亚洲国产黄色精品在线观看| 日本高清视频在线观看不卡| 国产一区二区精品高清免费| 中文人妻精品一区二区三区四区| 日韩18一区二区三区| 夫妻性生活黄色录像视频| 九九热在线免费在线观看| 伊人欧美一区二区三区| 激情五月激情婷婷丁香| 国产精品午夜福利免费阅读| 国产人妻熟女高跟丝袜| 国产成人午夜在线视频| 国产又色又爽又黄又大| 午夜国产福利在线播放| 国产伦精品一区二区三区高清版 | 久久黄片免费播放大全| 亚洲天堂国产精品久久精品| 日韩一区二区三区在线日| 国产精品不卡高清在线观看| 东京热加勒比一区二区三区| 午夜福利在线观看免费| 夜夜嗨激情五月天精品| 亚洲黑人精品一区二区欧美| 婷婷激情五月天丁香社区| 久久热中文字幕在线视频|