2011-06-29 28 views
6

由於Java 5,volatile關鍵字發佈/收購語義使副作用可見於其他線程(包括分配到非易失性變量!)。以這兩個變量,例如:揮發與釋放/收購語義

int i; 
volatile int v; 

注意i是有規律的,非易失性變量。試想一下,線程1執行以下語句:

i = 42; 
v = 0; 

在稍後的某個時間點,線程2執行以下語句:

int some_local_variable = v; 
print(i); 

根據Java內存模式,v在線程1寫然後在線程2中讀取v確保線程2看到在線程1中執行的寫入i,因此打印值42。

我的問題是:是否volatile在C#中具有相同的發佈/獲取語義?

+1

不完全;見http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx –

回答

14

C#中「volatile」的語義在規範的第3.10和10.4.3節中定義。我鼓勵你在規範中查找它,而不是在這裏重現它們,然後決定使用「volatile」並且回到使用鎖定過於複雜和危險。這就是我一直這樣做的。

請參閱3.10 Execution Order10.4.3 Volatile Fields規範。

+0

試圖迴避C++程序員從「複雜和危險」的細節可能會產生相反的效果;) – fredoverflow

+0

@Fred所以你只是在易變易感興趣,因爲它是複雜和危險的? –

+1

@David:我只是不喜歡不準確的知識,我的印象是'volatile'是有史以來最容易被誤解的關鍵字之一。我想知道東西是如何工作的,這都是:) – fredoverflow

6

好吧,我相信它可以確保如果some_local_variable讀爲0(由於寫v),i將被讀取爲42

棘手的部分是「在某個時間點」。雖然通常以「沖洗」寫入來討論波動性,但這不是它在spec(Java或C#)中實際定義的方式。

從C#4種語言的規範,第10.5.3節:

對於非易失性領域,優化技術,指令重新排序可導致訪問領域不同步多線程程序意外和不可預知的結果如鎖定語句(§8.12)提供的那樣。這些優化可以由編譯器,運行時系統或硬件來執行。對於易失性字段,此類重新排序優化受到限制:

  • 讀取易失性字段稱爲易失性讀取。易失性讀取具有「獲取語義」;也就是說,它確保在指令序列中出現在存儲器之後的任何引用之前。
  • 寫入易失性字段稱爲易失性寫入。易失性寫有「釋放語義」;也就是說,保證在指令序列中的寫入指令之前的任何存儲器引用之後發生。

有其然後是相當類似你,但是條件上從易失性可變讀出的值的例子。和埃裏克一樣,我強烈避免依靠易變本人。很難推理,最好留給世界的喬·達菲/史蒂芬·圖布斯。

+0

你能更具體地表達你的意思嗎尊重Java中的「沖洗」寫法?你是否暗示我的代碼甚至不能在Java中工作? – fredoverflow

+0

@Fred好吧,如果我們相信Jon的小引用,看起來C#確實可以保證寫入的釋放語義並獲取讀取的語義,這意味着該示例在Java和C#中都可以正常工作..現在,您仍然有去讀重要章節,以確保不會錯過某些角落案例。儘管我完全理解爲什麼避免不穩定(以及信號量和所有其他低級線程的東西)通常不是一個壞主意,但我也不想在我的知識中出現漏洞 - 而且只是因爲你知道如何使用volatile,不會你不需要! – Voo

+0

@Fred:問題是你還沒有定義「一段時間後」的含義。你可以保證的是,如果*線程2看到寫入volatile變量,那麼它將*看到寫入非易失性變量。 –