2009-06-26 127 views
176

看到各種鎖定相關的問題,(幾乎)總是查找術語我不知道「因爲虛假喚醒的循環」的,有沒有人經歷過這樣一種喚醒(假設例如一個體面的硬件/軟件環境)?真的發生虛假喚醒嗎?

我知道術語「僞」是指沒有明顯原因,但有什麼可以爲此類事件的原因是什麼?

(注:我不是質疑循環練習。)

編輯:一個輔助的問題(對於那些誰喜歡代碼示例):

如果我有以下程序,我運行它:

public class Spurious { 
    public static void main(String[] args) { 
     Lock lock = new ReentrantLock(); 
     Condition cond = lock.newCondition(); 
     lock.lock(); 
     try { 
      try { 
       cond.await(); 
       System.out.println("Spurious wakeup!"); 
      } catch (InterruptedException ex) { 
       System.out.println("Just a regular interrupt."); 
      } 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

有什麼事到虛假喚醒這個await,而不會永遠等待一個隨機事件?

回答

175

維基百科article on spurious wakeups有這麼一個小節目:

Linux中的pthread_cond_wait()功能使用futex系統調用來實現。當進程接收到信號時,Linux上的每個阻塞系統調用突然返回EINTR。 ... pthread_cond_wait()無法重新啓動等待,因爲它可能會在系統調用futex之外的很短時間內錯過真正的喚醒。這種競爭條件只能通過調用者檢查不變量來避免。 POSIX信號將因此產生虛假喚醒。

摘要:如果一個Linux的進程發送信號的等待線程將分別享受一個不錯的,熱虛假喚醒

我買它。這是一個容易吞嚥的藥丸,而不是通常模糊的「這是爲了表現」的原因。

8

Cameron Purdy寫了一個blog post一會兒又回到了被虛假喚醒問題打中。所以,是的,它發生

我猜它在規範(如可能),因爲其中一些Java的被部署在平臺上的限制?雖然我可能是錯的!

+5

http://www.jroller.com/cpurdy/entry/java_supplies_apologies_to_weird – akarnokd 2009-06-26 19:11:10

+0

我讀了這篇文章,並給了我一個想法,即單元測試通過隨機/確定性地喚醒單元測試來測試一個應用程序對循環等待範例的一致性。或者它已經在某個地方可用? – akarnokd 2009-06-26 19:17:28

+0

這是關於SO的另一個問題:「是否有*嚴格*虛擬機可用於測試?」。我很想看到一個嚴格的線程本地記憶 - 我不認爲它們還存在 – 2009-06-26 20:01:53

20

我有一個生產系統表現出這種行爲。 線程等待隊列中有消息的信號。 在繁忙時期,最多20%的喚醒是虛假的(即當它醒來時,隊列中沒有任何東西)。 此線程是消息的唯一使用者。 它運行在Linux SLES-10 8處理器盒子上,並使用GCC 4.1.2構建。 這些消息來自外部來源並被異步處理,因爲如果我的系統不夠快地讀取它們,會出現問題。

7

我想補充這一點。是的,它發生了,我花了三天時間在24核心機器(JDK 6)上尋找多線程問題的原因。 10次​​處決中有4次沒有任何模式。這從來沒有發生在2核心或8核心上。

研究了一些在線資料,這不是一個Java問題,而是一個罕見的但預期的行爲。

11

回答titile中的問題 - 是的!它happen.Though的Wiki article提到了一個很好的協議有關虛假喚醒了同樣的,我碰到如下一個很好的解釋 -

想想吧......像任何代碼,線程調度器可能會遇到由於底層硬件/軟件發生異常而暫時中斷。當然,應該注意這種情況儘可能少發生,但由於沒有100%強健的軟件這樣的事情,所以假設這種情況可能發生並且在調度器檢測到這種情況時保持優雅恢復是合理的(例如,通過觀察失蹤的心跳)。

現在,調度程序如何恢復,考慮到在停電期間它可能會錯過一些旨在通知等待線程的信號?如果調度程序什麼都不做,提到「不幸」的線程就會掛起,永遠等待 - 爲了避免這種情況,調度程序只會發送一個信號給所有等待的線程。

這使得有必要建立一個「合同」,可以無故通知等待線程。確切地說,會有一個原因 - 調度程序停電 - 但是由於線程被設計(出於一個很好的理由)忽略了調度程序的內部實現細節,這個原因可能更好地表現爲「虛假」。

我從Source看這個答案,發現它足夠合理。也讀

Spurious wakeups in Java and how to avoid them