2013-11-27 43 views
0

Java規範17.3睡眠和產量睡眠沒有同步語義嗎?

重要的是要注意的是沒有了Thread.sleep也不Thread.yield有任何同步語義。特別是,在調用Thread.sleep或Thread.yield之前,編譯器不必將寫入寄存器中的緩存刷新到共享內存中,編譯器也不必在調用Thread.sleep或Thread之後重新加載緩存在寄存器中的值。產量。

例如,在下面的(虛線)的代碼段中,假定this.done是非易失性布爾字段:

while (!this.done) 
    Thread.sleep(1000); 

編譯器可以自由地讀出的場this.done只需一次,和複用循環的每次執行中緩存的值。這意味着即使另一個線程更改了this.done的值,循環也不會終止。

問題:它在C#中是否一樣?

正如我們所知,我們可以添加Thread.MemoryBarrier();解決這個問題。

while(this.done) 
{ 
    Thread.MemoryBarrier(); 
    Thread.sleep(1000); 
} 

問題:不過是編譯器能夠識別在以下情況下的樂趣()作爲內存屏障?

public static void fun() 
{ 
    Thread.MemoryBarrier(); 
} 
while(this.done) 
{ 
    fun(); 
    Thread.sleep(1000); 
} 

,如果它是好的,爲什麼它不能識別睡眠作爲內存屏障,因爲它不能保證睡眠是否包含內存屏障?

+3

爲什麼*應該*'睡眠'有內存障礙? 「睡眠」有很多用途,其中很多用於輪詢變量(通常有更好的同步原語可用於跨線程信號傳輸) –

+0

@Damien_The_Unbeliever然後我的樂趣怎麼樣?它會被識別爲MemoryBarrier,因爲編譯器不知道它的內容?我只是覺得睡眠和其他功能應該被識別爲MemoryBarrier。 – Vince

+1

這是無稽之談,它是必須服從內存模型的抖動。當它可以將方法內聯到幾條機器代碼指令時,它肯定不會發出障礙,這將是可怕的。 –

回答

1

由於Sleep沒有明確聲明有任何這樣的語義,唯一安全的答案是「不要依賴它具有任何這樣的語義」。有很多方法可以安全地查詢變量或檢查其他標記(個人而言,我會試圖查看Monitor.Wait(obj, timeout),但YMMV)。你說:

我只是覺得sleep和其他功能應該被識別爲MemoryBarrier。

由於Sleep方法不聲稱做到這一點,你不能依賴它。這可能是因爲設計師不同意你的觀點。它可能是它甚至從來沒有出現討論(畢竟,這是一個相當武斷的影響)。

+0

我的樂趣怎麼樣()?它是否充當MemoryBarrier,雖然它在另一個程序集中? – Vince

+1

@Vince沒有說它會*,所以唯一安全的答案是「不,它不會」 –

+0

所以你的意思是,編譯器有一個MemoryBarrier函數列表,比如Thread.MemoryBarrier,Volatile .Read和Volatile.Write等。它不信任其他功能,雖然它們在內部包含MemoryBarrier? – Vince