91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#中Interlocked不能保證的事情

發布時間:2020-09-11 14:54:56 來源:網絡 閱讀:2042 作者:cnn237111 欄目:編程語言

本文的參考,來自于文章http://blogs.msdn.com/b/oldnewthing/archive/2004/09/15/229915.aspx


Interlocked類MSDN中對他的定義為:為變量在多線程共享的情況下提供原子操作。

很多人對于Interlocked的使用,僅限于Interlocked.Increment方法,這個方法在多線程環境下,總可以保證變量自增的正確性。

那么原子方法的定義是什么呢?顧名思義,原子一般認為是不可再分的,所以原子方法就是不可再分的方法,即在一個原子操作中,處理器能夠在一個指令傳輸中完成讀值和寫值, 也就是說,在原子操作完成之前,任何IO機制或處理器都不能對這個內存進行讀寫操作。原子操作常常被使用于大多數操作系統的內核和基礎類庫中,而且大多數的計算機硬件,編譯器和類庫都支持了各個層面上的原子操作。

很多人認為使用原子操作能夠保證多線程下的數據的正確性。那么看下面的代碼:

class Program
{
static private object _obj = new object();
static void Main(string[] args)
{
int count = 0;
for (int i = 0; i < 10000; i++)
{
int x = 2;
Task t1 = Task.Factory.StartNew(() => { InterlockedMultiply(ref x, 10); });
Task t2 = Task.Factory.StartNew(() => { Interlocked.Increment(ref x); });
Task.WaitAll(t1, t2);
if (x != 21 && x != 30)
{
Console.WriteLine(x); 
count++;
}
}
Console.WriteLine("值不為21且不為30的次數:"+count);
Console.WriteLine("done!");
}
static void InterlockedMultiply(ref int x, int y)
{
lock (_obj)
{
x = x * y;
}
}
}

上述代碼中,循環體中,開2個task,可以認為是2個線程,這2個線程運行2個方法,一個是原子方法,另一個是加了鎖的方法。

先用常規的思路分析一下:

由于t2是原子操作,所以保證x的值可以被自增,不會受其他線程的干擾,t1中運行的方法是InterlockedMultiply,并加入lock。

當方法運行的時候,要么是t1先運行,要么是t2先運行,所以,要么值為(2+1)*10=30,要么值為(2*10)+1=21。

 

但是當運行的時候,循環10000次后,結果為:

C#中Interlocked不能保證的事情

值不為21且不為30的次數:103。 

導致這種問題的原因,在于InterlockedMultiply的實現,看下面的細節圖

C#中Interlocked不能保證的事情

當t2在讀取完x的后,把該值讀到寄存器中,寄存器中的值為2了,而t1中的原子操作對x做了自增,也就是說此時x是3了,接著,t2線程在寄存器中把該值乘以10后,寫入到內存,然后下一個時刻釋放鎖,此時就把之前的值有覆蓋成20了。

也就是說雖然2個線程中的代碼都是各自獨立的,但是在并發情況下,還是不能保證值的正確性。原因如下:

1.由于我們模擬的InterlockedMultiply方法中的操作,并不具備原子性。雖然加了lock,但是對于那些無需獲取鎖就能訪問x的函數體來說,它們是可以直接修改x的。也就是說,這里加了lock也沒什么用。

2.Interlocked.Increment能夠保證的是該操作是原子性的,在它將值設為3的期間,不會有其他操作讀寫x。這點很重要,如果這點不能保證,那么上面的情況中會出現:

假設原本step6,step7中的操作在step5期間進行,當t2的操作快于t1先完成時,那么X的值先被設成了20,然后又立刻被t1設成了3,這就導致了值會是3的情況出現。

3.雖然Interlocked.Increment使得x的自增具備原子性,但它不能夠保證的是:但它不能夠保證的是:其他線程在操作x時,拿到的x的值是最新的

 

基于上面的分析,可以得出一個結論,多線程下的并發編程,需要考慮的更周到,原子操作并不保證多線程環境下的值總是對的。

 

如果要實現上面的InterlockedMultiply方法,參考文檔中的寫法是采用了do while的循環,這個操作就使得t2線程在那邊不斷的重試,其實也不是最好的辦法。我能想到的辦法是把t2中也加鎖:

Task t2 = Task.Factory.StartNew(() => { lock (_obj) { Interlocked.Increment(ref x); } });

但是這種辦法也不好,使得線程不能正真的同時運行,總有一個陷于等待中。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博乐市| 临汾市| 运城市| 石台县| 五莲县| 绥化市| 绥芬河市| 玉屏| 道孚县| 中牟县| 台湾省| 治县。| 中卫市| 乐至县| 西城区| 隆回县| 泸西县| 崇礼县| 南昌市| 广灵县| 垣曲县| 洪泽县| 合川市| 柞水县| 榆林市| 吐鲁番市| 昌吉市| 宕昌县| 双城市| 徐水县| 育儿| 锦屏县| 鄂州市| 衡阳市| 南陵县| 马边| 广东省| 保亭| 上高县| 武山县| 龙南县|