C# 原子操作理解
阿新 • • 發佈:2019-05-10
turn 其他 暫時 ram result sta 最大值 兩個 變量
C#內置提供的原子操作
- Interlocked.Increment:以原子操作的形式遞增指定變量的值並存儲結果。
- Interlocked.Decrement:以原子操作的形式遞減指定變量的值並存儲結果。
- Interlocked.Add:以原子操作的形式,添加兩個整數並用兩者的和替換第一個整數
問題:如果要進行原子的乘法、除法或者其他操作改怎麽辦,C#並沒有內置提供相應的方法呀?
那我們先來大概理解一下原子操作的流程
以增加變量值為例
- 將實例變量添加到CPU寄存器中
- 將該變量的值進行增加
- 將該變量的增加後的值從CPU寄存器中還原到堆或棧中實例變量的值
可以看到如果是多核CPU在多線程環境下可能會導致在執行完步驟1,步驟2後當前線程失去時間片,其他線程讀取改變量的值時就會讀取到並未增加增加之前的值,所以就導致了數據的不一致。然而C#提供了上面三種原子操作來保證不出現這樣的數據不一致,至於底層原理暫時不深究,我們來看看如何實現除這三種方法之外的操作。
進行原子的獲取最大值操作
先放代碼如下:
public static int Maximum(ref int target, int value) { //註意target前面加了 ref ,這樣在方法外改變target的值將會影響到方法內的target值, //即類似按引用傳遞 int currentVal = target;//使用currentVal局部變量來存儲target值,target值的變更不會影響currentVal int startVal = 0; int desiredVal = 0; do { startVal = currentVal; //記錄本次叠代的起始值 1 desiredVal = Math.Max(startVal, value);//根據startVal和value計算最大值desiredVal 2 //如果target和startVal值一致則用desiredVal賦值給target,並將target原始值進行返回 //如果target和startVal值不相同則什麽都不做,並將target的值進行返回 //target的值因為在別的線程進行操作時可能改變target的值,所以導致target值和startVal不一致 currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);// 3 } while (startVal != currentVal); // 4 //因為startVal記錄的是開始時target的值,而currentVal記錄的則是target最新值 //如果startVale和currentVal不一致則代表其他線程已經更改的target的值,所以需要重新叠代。 //重新叠代時currentVal代表的是target的最新值 //疑問:如果在 3 之後 4之前 target的值被其他線程更改怎麽辦?請大神幫忙 return desiredVal; }
大致的邏輯可以參考註釋進行理解,最主要的方法是通過currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); 可以參考MSDN此方法的解釋
其他操作
C# VIA CLR中給出了其他操作的模板,可以參考如下:
delegate int Morpher<TResult, TArgument>(int startValue, TArgument argument, out TResult morphResult); static TResult Morph<TResult,TArgument>(ref int target,TArgument argument,Morpher<TResult,TArgument> morpher) { TResult morphResult; int currentVal = target; int startVal = 0; int desiredVal = 0; do { startVal = currentVal; desiredVal = morpher(startVal, argument, out morphResult); currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); } while (startVal != currentVal); return morphResult; }
可以通過委托定義自己想要的操作。乘法、除法等等。
大神寫出的書就是牛,膜拜Jeffrey Richter
C# 原子操作理解