[英]Interlocked.Exchange clarification
我有一些簡單(希望)的問題,我一直無法找到答案 -
假設我有多個線程可以訪問的對象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規范實際上定義了一個較弱的模型,其中寫入默認情況下不是易失性的“。
這是真的? 如果是這樣,如果不關心'a'的先前值,是否有Interlocked.Exchange的目的? (與我的第一個例子有關)。 我沒有在StackOverflow上看到任何關於每個寫入易失性的文章或評論。 但是,我知道寫入是原子的。
編輯:如果我的第一個問題的答案是“b”不被視為易失性,而我的第二個問題的答案是寫入確實是不穩定的,那么跟進就是,什么時候是聯鎖的。如果我們不這樣做,則有用關心'a'的先前價值?
傳遞給Exchange
的變量(或傳遞給任何方法的任何volatile變量)在傳遞時不會保留“volatile”...實際上不需要它是volatile
(在方法調用期間)因為唯一的volatile
確保編譯器不優化變量的使用(這通常意味着優化寫入寄存器,因此值只能由單個處理器“看到”)。 在x86 / x64以外的處理器上,這有時意味着保證獲取或釋放語義的指令。 .NET不使用寄存器進行參數傳遞,因此volatile不會影響傳遞的參數的“波動性”。 由於內存模型的可見性保證,它必須始終從內存中獲取最新值
RE問題2:引用是“真實的”,取決於字段的聲明,有可見性保證wrt字段; 但是沒有“volatile”字段訪問可以在某些使用階段被優化到寄存器中,可能隱藏來自其他處理器的某些寫入。
Interlocked
交換使非原子的操作看起來是原子的。 交換本質上類似於:
var x = someVariable;
someVariable = y;
無論someVariable
的類型如何,這都不可能是原子的。 Exchange
使此操作成為原子。 這也是非原子類型的原子,如double
, long
(32位)等。
Exchange
使用這個原子的部分原因是使用內存柵欄 - 這使得寫入可見而不是重新排序,並且在內存柵欄之后的指令序列中讀取相同的內存地址。
如果您不關心“a”的先前值,為什么要使用Exchange
? 如果你不關心實際的“交換”,那么VolatileWrite
似乎更合適。
或者,如果不需要“交換”,您可以編寫線程安全代碼來模擬“A = B”,如下所示:
Thread.MemoryBarrier();
A=B;
FWIW, Interlocked
部分模擬了某些處理器中的比較和交換(CAS)指令。 這些指令允許您在一條指令中執行這兩項操作(使其成為原子)。 如果沒有像Interlocked
這樣的東西,編譯器可能很難推斷出應該使用這些CAS指令之一。 此外, Interlocked
在不支持這些CAS指令的處理器上提供原子使用(以及其他可能非原子指令,如inc和dec - 可能並非在所有處理器上都可用)
如果'b'不是易變的,這個操作會不會這樣處理?
當b
是共享變量時,我認為你不應該使用它。 這樣就消除了整個問題。 但Exchange總會使用Memorybarrier,所以答案可能是肯定的。
何時是interlocked.exhange有用,如果我們不關心'a'的先前值?
double
的重載非常有用,因為寫入double
不是原子的。 32位系統上的Int64也是如此。
但是對於原子類型的Exchange()
重載,用例不太清楚。 我認為大多數算法都支持CompareExcange()
。
所以考慮一下原子Write()。
如果'b'不是易變的,這個操作會不會這樣處理?
是的,因為根據這個來源 , Interlocked
類的所有方法都會生成隱式內存柵欄。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.