簡體   English   中英

.Net CompareExchange重新排序

[英].Net CompareExchange reordering

編譯器或處理器是否可以重新排序以下指令,以便另一個線程看到a == 0b == 1

假設int a = 0, b = 0; 某處。

System.Threading.Interlocked.CompareExchange<int>(ref a, 1, 0);
System.Threading.Interlocked.CompareExchange<int>(ref b, 1, 0);

不可以。使用Interlock會發出完整的內存柵欄信號。 “也就是說,之前調用的任何變量寫入Interlocked方法中的之前執行Interlocked方法,以及該呼叫的呼叫之后,執行之后的任何變量的讀取。” [1],他們使用揮發性讀/寫方法,以防止在b = 1之前a = 1

[1]:Jeffrey Richter:“CLR通過C# - 第三版”第V部分線程,第803頁

當然可以。 組成CompareExchange操作的各個操作無法被可觀察地重新排序,但是對於CompareExchange的兩次調用可以從另一個線程的角度重新排序,只要執行此代碼的線程無法觀察到這種行為。

CompareExchange的同步工具阻止了影響與該操作相關的內存位置的操作之間的可觀察重新排序,而不是一般的任何操作,也沒有任何代碼阻止編譯器或JITter完全重新排序這兩個CompareExchange調用(從另一個線程的角度來看)。

你正在閱讀太多的理論。 是的,如果其他線程可以在實踐中發生

Console.WriteLine("a: {0}, b: {1}", a, b);

由於用於格式化字符串的String.Format具有簽名

   String Format(string fmt, params object[] args)
   {
       ....
   }

由於拳擊你的整數將被復制。 唯一需要滿足的條件是線程時間片在復制了其單位化狀態時結束。 稍后當線程恢復工作時,兩個變量都設置為1,但控制台輸出將是

a: 0, b: 1

如果您在沒有意識到的情況下處理值的副本,則立即發現其他值的觀點。 這就是為什么你通常讓其他人寫正確的無鎖代碼的原因。 如果您嘗試使用Console.WriteLine調試無鎖代碼,我希望您好運。

雖然a和b按順序設置(我不認為JIT編譯器會重新排序你的互鎖調用)但你不能保證其他線程只能看到兩個零或兩個零。 您可以嘗試先讀取b並檢查它是否具有值1,然后您可以推導出a的值,但在這種情況下,您甚至不需要a的值。 至少對於x86內存模型應該如此。 這種假設可以通過ARM等較弱的內存模型來打破。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM