簡體   English   中英

被 pthread_cond_signal() 喚醒但失去互斥鎖競爭的線程會發生什么

[英]What happens to a thread that got woken up by pthread_cond_signal() but lost competition for a mutex

關於這個: 如何使用條件變量

假設我們有多個執行此類代碼的消費者線程(從引用的頁面復制):

while (TRUE) {
    s = pthread_mutex_lock(&mtx);
    while (avail == 0) {   /* Wait for something to consume */
       s = pthread_cond_wait(&cond, &mtx);
    }
    while (avail > 0) {   /* Consume all available units */ 
        avail--;
    }
    s = pthread_mutex_unlock(&mtx);
}

我假設這里的場景是:主線程調用 pthread_cond_signal() 來告訴消費者線程做一些工作。

據我了解 - 后續線程調用 pthread_mutex_lock() 然后調用 pthread_cond_wait() (它以原子方式解鎖互斥鎖)。 到目前為止,沒有一個消費者線程正在聲明互斥鎖,它們都在等待 pthread_cond_wait()。

當主線程調用 pthread_cond_signal() 時,按照手冊頁,至少有一個線程被喚醒。 當它們中的任何一個從 pthread_cond_wait() 返回時,它會自動聲明互斥鎖。

所以我的問題是:關於提供的示例代碼現在會發生什么? 即,在互斥鎖競爭中輸掉的線程現在在做什么?

(AFAICT 贏得互斥鎖的線程,應該運行代碼的 rest 並釋放互斥鎖。丟失的線程應該卡在互斥鎖上等待 - 在第一個嵌套while循環中的某個地方 - 而獲勝者持有它並在它之后在 pthread_cond_wait() 上釋放開始阻塞,因為屆時將滿足while (avail == 0) 。我正確嗎?)

請注意, pthread_cond_signal()通常僅用於喚醒一個等待線程(這就是它所保證的全部)。 但它可能會更“意外”地醒來。 while (avail > 0)循環執行兩個功能:

  • 它允許保證喚醒的一個線程消耗所有排隊的工作單元
  • 它可以防止其他“意外”喚醒的線程假設有工作要做,而實際上可能沒有工作,因為初始線程會處理所有這些工作。

它還可以防止在while (avail > 0)完成之后,但在工作線程再次等待條件之前,工作單元可能已被放置在隊列中的競爭條件 - 但該競爭也由if測試處理就在調用pthread_cond_wait()之前。

基本上,當一個線程被喚醒時,它所知道的只是可能有工作單元可供它使用,但可能沒有(另一個線程可能已經消耗了它們)。

所以調用pthread_cond_signal()時發生的事件序列是:

  • 系統將喚醒一個或多個等待條件的線程
  • 然后,所有被喚醒的線程都將嘗試獲取互斥鎖 - 只有其中一個線程可以在任何特定時刻獲取它,因為這是互斥鎖的目的
  • 然后該線程將繼續,在while (avail > 0)循環中執行工作,然后將釋放互斥鎖
  • 此時,先前喚醒的其他線程之一將獲取互斥鎖並工作相同的循環,然后釋放互斥鎖。 通常,將不再有可用的工作單元(因為第一個線程會消耗所有工作單元),但如果另一個線程添加了一個額外的單元(或更多),那么這個線程將處理該工作
  • 下一個線程將獲取互斥體並執行同一組邏輯

一旦發出信號/喚醒, pthread_cond_wait()必須獲取給定的互斥鎖。 如果另一個線程贏得了比賽,function 將阻塞,直到互斥鎖被釋放。 因此,從應用程序的角度來看,在當前線程持有互斥鎖之前它不會返回。 等待總是在循環中完成( while (avail == 0) {... above)以確保我們等待的應用程序條件仍然成立(緩沖區不為空,更多工作可用等)

希望這可以幫助。

一旦互斥鎖被解鎖,輸掉比賽的線程就會醒來,再次檢查條件,然后在條件變量上進入睡眠狀態。

當它們中的任何一個從 pthread_cond_wait() 返回時,它會自動聲明互斥鎖。

啊,但事實並非如此。 不是“自動”,也就是說,取決於“自動”的含義。 您可能會對pthread_cond_wait的“原子”語義感到困惑; 但是該語義在入口端發揮作用:在放棄互斥鎖之前,以某種方式注冊了一個線程等待條件,因此沒有任何 window 在此期間線程不再具有互斥鎖,並且尚未等待在變量上。

pthread_cond_wait返回的每個線程都必須獲取互斥體並因此爭奪它。 那些失去互斥鎖競爭的人必須阻塞互斥鎖,就像他們調用pthread_mutex_lock一樣。

pthread_cond_wait退出時獲取互斥鎖的方式可以建模為常規pthread_mutex_lock操作。 本質上,線程必須在互斥體上排隊才能退出。 每個獲取互斥鎖的線程然后從 function 返回; 其他人必須等到該線程放棄互斥體才能返回。

沒有被信號喚醒的線程“自動”獲得互斥鎖,在某種意義上,由於特殊資格而以某種方式轉移了所有權。 首先,在多處理器上,被喚醒的線程可能會失去與已經在另一個處理器上運行的線程的競爭,該線程搶奪互斥鎖(如果可用),或者在接收信號的線程之前排隊等待互斥鎖。 其次,調用pthread_cond_signal的線程可能本身並沒有放棄互斥鎖,並且可能會繼續無限期地持有它,這意味着所有被喚醒的線程都將排隊等待互斥鎖操作,並且沒有一個線程會從pthread_mutex_lock中出現,直到該線程放棄互斥體。

所有“自動”是pthread_cond_wait操作在再次獲取互斥鎖之前不會返回,因此應用程序不必采取獲取互斥鎖的步驟。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM