国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

多線程中的鎖系統(二)-volatile、Interlocked、ReaderWriterLockSlim

2019-11-17 02:40:04
字體:
來源:轉載
供稿:網友

多線程中的鎖系統(二)-volatile、Interlocked、ReaderWriterLockSlim

2015-01-01 23:16 by 蘑菇先生, ... 閱讀, ... 評論, 收藏, 編輯

上章主要講排他鎖的直接使用方式。但實際當中全部都用鎖又太浪費了,或者排他鎖粒度太大了,本篇主要介紹下升級鎖和原子操作。

閱讀目錄

  1. volatile
  2. Interlocked
  3. ReaderWriterLockSlim

volatile

簡單來說volatile關鍵字是告訴c#編譯器和JIT編譯器,不對volatile標記的字段做任何的緩存。確保字段讀寫都是原子操作,最新值。

從功能上看起到鎖的作用,但它不是鎖, 它的原子操作是基于CPU本身的,非阻塞的。 因為32位CPU執行賦值指令,數據傳輸最大寬度4個字節。

所以只要在4個字節以下讀寫操作的,32位CPU都是原子操作,volatile 是利用這個特性來保證其原子操作的。

這樣的目的是為了提高JIT性能效率,對有些數據進行緩存了(多線程下)。

       //正確       public volatile Int32 score1 = 1;        //報錯        public volatile Int64 score2 = 1;

如上,我們嘗試定義了8個字節長度score2,會拋出異常。 因為8個字節32位CPU就分成2個指令執行了,所以就無法保證其原子操作了。

如果把編譯平臺改成64位,同樣不可以使用,C#限制4個字節以下的類型字段才能用volatile。

還一種方法是使用特定平臺的整數類型IntPtr,這樣volatile即可作用到64位上了。

volatile多數情況下很有用處的,畢竟鎖的性能開銷還是很大的。可以把當成輕量級的鎖,根據具體場景合理使用,能提高不少程序性能。

線程中的Thread.VolatileRead 和Thread.VolatileWrite 是volatile以前的版本。

Interlocked

MSDN 描述:為多個線程共享的變量提供原子操作。主要函數如下:

Interlocked.Increment    原子操作,遞增指定變量的值并存儲結果。Interlocked.Decrement   原子操作,遞減指定變量的值并存儲結果。Interlocked.Add       原子操作,添加兩個整數并用兩者的和替換第一個整數

Interlocked.CompareExchange(ref a, b, c); 原子操作,a參數和c參數比較, 相等b替換a,不相等不替換。

下面是個interlock anything的例子:

public static int Maximum(ref int target, int value)        {            int currentVal = target, startVal, desiredVal;  //記錄前后值            do            {                startVal = currentVal; //記錄循環迭代的初始值。                desiredVal = Math.Max(startVal, value); //基于startVal和value計算期望值desiredVal                //高并發下,線程被搶占情況下,target值會發生改變。                //target startVal相等說明沒改變。desiredVal 直接替換。                currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);            } while (startVal != currentVal); //不相等說明,target值已經被其他線程改動。自旋繼續。            return desiredVal;        }

ReaderWriterLockSlim

假如有份緩存數據A,如果每次都不管任何操作lock一下,那么我的這份緩存A就永遠只能單線程讀寫了, 這在Web高并發下是不能忍受的。

那有沒有一種辦法我只在寫入時進入獨占鎖呢,讀操作時不限制線程數量呢?答案就是我們的ReaderWriterLockSlim主角,讀寫鎖。

ReaderWriterLockSlim其中一種鎖EnterUpgradeableReadLock最關鍵 即可升級鎖。

它允許你先進入讀鎖,發現緩存A不一樣了, 再進入寫鎖,寫入后退回讀鎖模式。

ps: 這里注意下net 3.5之前有個ReaderWriterLock 性能較差。推薦使用升級版的ReaderWriterLockSlim 。

//實例一個讀寫鎖 ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

上面實例一個讀寫鎖,這里注意的是構造函數的枚舉。

LockRecursionPolicy.NoRecursion 不支持,發現遞歸會拋異常。

LockRecursionPolicy.SupportsRecursion 即支持遞歸模式,線程鎖中繼續在使用鎖。

            cacheLock.EnterReadLock();            //do                 cacheLock.EnterReadLock();                //do                cacheLock.ExitReadLock();            cacheLock.ExitReadLock();

這種模式極易容易死鎖,比如讀鎖里面使用寫鎖。

      cacheLock.EnterReadLock();            //do               cacheLock.EnterWriteLock();              //do              cacheLock.ExitWriteLock();            cacheLock.ExitReadLock();

下面是msdn的緩存例子了,加了注釋。

public class SynchronizedCache    {        PRivate ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();        private Dictionary<int, string> innerCache = new Dictionary<int, string>();        public string Read(int key)        {            //進入讀鎖,允許其他所有的讀線程,寫入線程被阻塞。            cacheLock.EnterReadLock();            try            {                return innerCache[key];            }            finally            {                cacheLock.ExitReadLock();            }        }        public void Add(int key, string value)        {            //進入寫鎖,其他所有訪問操作的線程都被阻塞。即寫獨占鎖。            cacheLock.EnterWriteLock();            try            {                innerCache.Add(key, value);            }            finally            {                cacheLock.ExitWriteLock();            }        }        public bool AddWithTimeout(int key, string value, int timeout)        {            //超時設置,如果在超時時間內,其他寫鎖還不釋放,就放棄操作。            if (cacheLock.TryEnterWriteLock(timeout))            {                try                {                    innerCache.Add(key, value);                }                finally                {                    cacheLock.ExitWriteLock();                }                return true;            }            else            {                return false;            }        }        public AddOrUpdateStatus AddOrUpdate(int key, string value)        {            //進入升級鎖。 同時只能有一個可升級鎖線程。寫鎖,升級鎖都被阻塞,但允許其他讀取數據的線程。            cacheLock.EnterUpgradeableReadLock();            try            {                string result = null;                if (innerCache.TryGetValue(key, out result))                {                    if (result == value)                    {                        return AddOrUpdateStatus.Unchanged;                    }                    else                    {                        //升級成寫鎖,其他所有線程都被阻塞。                        cacheLock.EnterWriteLock();                        try                        {                            innerCache[key] = value;                        }                        finally                        {                            //退出寫鎖,允許其他讀線程。                            cacheLock.ExitWriteLock();                        }                        return AddOrUpdateStatus.Updated;                    }                }                else                {                    cacheLock.EnterWriteLock();                    try                    {                        innerCache.Add(key, value);                    }                    finally                    {                        cacheLock.ExitWriteLock();                    }                    return AddOrUpdateStatus.Added;                }            }            finally            {                //退出升級鎖。                cacheLock.ExitUpgradeableReadLock();            }        }        public enum AddOrUpdateStatus        {            Added,            Updated,            Unchanged        };    }

多線程實際開發當中一直是個難點,特別是并發量比較高的情況下,這需要使用時尤為注意。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阜平县| 炉霍县| 特克斯县| 比如县| 武功县| 双辽市| 南召县| 漳浦县| 黑山县| 类乌齐县| 峡江县| 长春市| 龙岩市| 井冈山市| 蒙阴县| 梧州市| 翼城县| 安顺市| 孟连| 宽甸| 陇西县| 福贡县| 黔南| 买车| 东至县| 中西区| 苏州市| 凌云县| 尼玛县| 南丹县| 上蔡县| 阜康市| 府谷县| 萨迦县| 泾源县| 边坝县| 鄂温| 永顺县| 潞西市| 太原市| 长海县|