2012-10-22 107 views
3

我有幾個簡單的(希望),我一直無法找到答案的提問 -Interlocked.Exchange澄清

說我有對象A,B是多個線程訪問。

Interlocked.Exchange(ref a, b) 

如果'b'不是易失性的,那麼這個操作會如何對待它?即它會從內存中獲取這個變量的最新值嗎?如果是這樣,這是寫與讀'原子'?據我所知,Interlocked.Exchange的主要目的是,你會得到「A」的前值作爲新寫一個原子操作。但我的主要困惑在於'b'的實際寫入'a'的價值。

我的第二個問題是有關報價在這篇文章中:

http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

「一個有趣的一點是,在C#中所有的寫操作是揮發性根據內存模型,在這裏和這裏記錄在案,並也大概是作爲這樣實現。C#語言的ECMA規範實際上定義較弱的模型,其中寫操作不是默認揮發性「。

這是真的嗎?如果是這樣,有Interlocked.Exchange的目的,如果不關心「A」的前值? (屬於我的第一個例子)。在每個寫操作都不穩定的時候,我沒有看到任何其他文章或有關StackOverflow的評論。然而,我明白寫道是原子的。

編輯:如果我的第一個問題的答案是'b'不被視爲易失性的,並且我的第二個問題的答案是寫入確實是不穩定的,那麼後續是當互鎖.exhange有用如果我們不關心'a'的先前價值?

+0

'b'的'揮發性' '應該沒關係。 –

回答

7

傳遞給Exchange(或傳遞給任何方法的任何易失性變量)的變量在傳遞時不保留「volatile」......實際上並不需要它是volatile(因爲方法調用期間),因爲volatile所做的只是確保編譯器不會優化變量的使用(通常意味着優化寫入寄存器的操作,因此只能由單個處理器「看到」)。在x86/x64以外的處理器上,這有時意味着保證獲取或釋放語義的指令。 .NET不使用寄存器傳遞參數,因此volatile不會影響傳遞參數的「波動性」。由於內存模型的可視性保證,它必須始終從內存獲取最新值

RE問題2:引用是「有點」真,取決於字段的聲明,有可見性保證w.r.t.領域;但沒有「易失性」字段訪問可以在某些使用階段優化到寄存器中,可能會隱藏某些來自其他處理器的寫入。

Interlocked交換使得非原子操作看起來是原子的。交易所本質上是類似於:

var x = someVariable; 
someVariable = y; 

這不可能是原子無論someVariable類型。 Exchange使此操作成爲原子。這也是原子與非原子類型,如doublelong(32位)等

什麼Exchange確實使這一部分的原子是使用內存圍欄 - 這使得寫入可見,而不是重新在內存圍欄之後的指令序列中,讀取相同的內存地址。

如果您不關心'a'的前值,爲什麼要使用Exchange?如果你不關心實際的「交換」,那麼VolatileWrite似乎更合適。

或者,如果不需要「交流」,您可以編寫線程安全的代碼模型「A = B」的方法如下:

Thread.MemoryBarrier(); 
A=B; 

FWIW,Interlocked部分仿照周圍比較並交換(CAS)指令在一些處理器中。這些指令允許您在一條指令中執行這兩個操作(使其成爲原子)。如果沒有像Interlocked這樣的東西,編譯器可能很難推斷應該使用這些CAS指令之一。另外,Interlocked在不支持這些CAS指令的處理器上提供了原子用法(以及其他潛在的非原子指令,如inc和dec - 可能並不適用於所有處理器)

+0

感謝您的回覆。如果你不關心之前的值,爲什麼你要使用交換的問題 - 如果B不是揮發性的,但我們想確保我們不將A設置爲緩存的B值,那麼該怎麼辦?如果問題2只是'真實',那麼不會設置A這種方式可能會不同於設置A = B? – user981225

+0

如果你不關心之前的值,'Volatile.Write'可能更合適 - 儘管我不認爲它支持所有與Exchange相同的類型。使用'VolatileWrite'或'Interlocked.Exchange'(或'lock'或'volatile')將值寫入其他線程可見的字段總是更安全。 –

1

如果「B」不揮發,在此操作對待它?

我不認爲你應該永遠不要使用這個,當b是一個共享變量。這樣就消除了整個問題。但Exchange總是會使用Memorybarrier,所以答案可能是Yes。

,如果我們不關心「A」的前值時,是interlocked.exhange有用嗎?

double的過載是非常有用的,因爲寫入double否則不是原子的。 32位系統上的Int64也一樣。

但對原子類型的Exchange()重載使用情況還不太清楚。我認爲大多數算法會支持CompareExcange()

所以認爲它的原子寫()。

+0

謝謝。你能解釋一下爲什麼當b是一個共享變量時你不認爲這應該被使用? – user981225

+0

轉過身:何時/爲什麼要將共享B寫入共享A? –

+0

當你這樣說:)時有道理 – user981225

1

如果'b'不是易失性的,那麼這個操作會如何對待它?

是的,因爲根據this source,該Interlocked類的所有方法生成內隱記憶柵欄。

+0

謝謝。這是否也意味着B值的讀數是原子的,並將該值寫入A?或者在分配給A之前,B的價值在技術上還是可以改變的? – user981225

+0

@ user981225:那麼'b'是通過值傳遞給方法的,所以方法調用後的任何改變都不會干擾方法接收到的值。 – Tudor