亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#多線程編程中的鎖系統(tǒng)(二)

 更新時間:2015年04月10日 09:37:39   投稿:junjie  
這篇文章主要介紹了C#多線程編程中的鎖系統(tǒng)(二),本文講解了volatile、Interlocked、ReaderWriterLockSlim等升級鎖和原子操作的使用實例,需要的朋友可以參考下

上章主要講排他鎖的直接使用方式。但實際當中全部都用鎖又太浪費了,或者排他鎖粒度太大了。 這一次我們說說升級鎖和原子操作。

目錄
1:volatile
2:  Interlocked
3:ReaderWriterLockSlim
4:總結(jié)

一:volatile

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

這不就是鎖嗎?   其這貨它根本不是鎖, 它的原子操作是基于CPU本身的,非阻塞的。 因為32位CPU執(zhí)行賦值指令,數(shù)據(jù)傳輸最大寬度4個字節(jié)。

所以只要在4個字節(jié)以下讀寫操作的,32位CPU都是原子操作。volatile 它就是利用這個特性來的。

好殘酷的事實?不然,微軟大法這樣是為了提高JIT性能效率,對有些數(shù)據(jù)進行緩存了(多線程下)。

復(fù)制代碼 代碼如下:

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

看上面的例子,我們定義8個字節(jié)長度score2就不行了。  因為8個字節(jié),32位CPU就分成2個指令執(zhí)行了。自然就無法保證原子操作了。

這么細節(jié)的,忘了怎么辦,那豈不是坑人啊。  于是微軟大法直接一棍子打死,限制4個字節(jié)以下的類型字段才能用volatile,具體什么、看msdn吧。

那今天我知道了。我編譯平臺改成64位上,只在64位CPU用volatile  int64,行不行?  不行,編譯器報錯。說了一棍子打死了。。

(^._.^)ノ  好吧,其實可以用IntPtr這個。

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

線程中的Thread.VolatileRead 和Thread.VolatileWrite 就是volatile的復(fù)雜版。

二:Interlocked

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

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

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

基本用法就不多說了。直接來段CLR via C# interlock anything的例子:

復(fù)制代碼 代碼如下:

public static int Maximum(ref int target, int value)
        {
            int currentVal = target, startVal, desiredVal;  //記錄前后值
            do
            {
                startVal = currentVal; //記錄循環(huán)迭代的初始值。
                desiredVal = Math.Max(startVal, value); //基于startVal和value計算期望值desiredVal

                //高并發(fā)下,線程被搶占情況下,target值會發(fā)生改變。

                //target startVal相等說明沒改變。desiredVal 直接替換。
                currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);

            } while (startVal != currentVal); //不相等說明,target值已經(jīng)被其他線程改動。自旋繼續(xù)。
            return desiredVal;
        }

三:ReaderWriterLockSlim

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

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

ReaderWriterLockSlim 其中一種鎖EnterUpgradeableReadLock最關(guān)鍵  即可升級鎖。 

它呢允許你先進入讀鎖,發(fā)現(xiàn)緩存A不一樣了, 再進入寫鎖,寫入后退回讀鎖模式。

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

復(fù)制代碼 代碼如下:

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

上面實例一個讀寫鎖,這里注意的是構(gòu)造函數(shù)的枚舉。

LockRecursionPolicy.NoRecursion 不支持,發(fā)現(xiàn)遞歸會拋異常。

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

復(fù)制代碼 代碼如下:

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

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

復(fù)制代碼 代碼如下:

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

下面是直接拿msdn的緩存例子了,加了簡單注釋。

復(fù)制代碼 代碼如下:

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)
        {
            //進入寫鎖,其他所有訪問操作的線程都被阻塞。即寫?yīng)氄兼i。
            cacheLock.EnterWriteLock();
            try
            {
                innerCache.Add(key, value);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
        }

        public bool AddWithTimeout(int key, string value, int timeout)
        {
            //超時設(shè)置,如果在超時時間內(nèi),其他寫鎖還不釋放,就放棄操作。
            if (cacheLock.TryEnterWriteLock(timeout))
            {
                try
                {
                    innerCache.Add(key, value);
                }
                finally
                {
                    cacheLock.ExitWriteLock();
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public AddOrUpdateStatus AddOrUpdate(int key, string value)
        {
            //進入升級鎖。 同時只能有一個可升級鎖線程。寫鎖,升級鎖都被阻塞,但允許其他讀取數(shù)據(jù)的線程。
            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
        };
    }

四:總結(jié)

多線程實際開發(fā)當中,往往測試沒問題,一到生產(chǎn)環(huán)境,并發(fā)高了就容易出問題, 一定注意。

本文參考CLR via C#。

相關(guān)文章

  • C#操作windows注冊表的方法

    C#操作windows注冊表的方法

    這篇文章主要介紹了C#操作windows注冊表的方法,涉及C#針對注冊表的讀取與寫入技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • C#實現(xiàn)撲克游戲(21點)的示例代碼

    C#實現(xiàn)撲克游戲(21點)的示例代碼

    21點又名黑杰克,該游戲由2到6個人玩,使用除大小王之外的52張牌,游戲者的目標是使手中的牌的點數(shù)之和不超過21點且盡量大。本文將用C#實現(xiàn)這一經(jīng)典游戲,需要的可以參考一下
    2022-08-08
  • C#分布式事務(wù)的超時處理實例分析

    C#分布式事務(wù)的超時處理實例分析

    這篇文章主要介紹了C#分布式事務(wù)的超時處理,以實例形式較為詳細的分析了C#分布式事務(wù)的超時處理相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • DevExpress之ChartControl的SeriesTemplate實例

    DevExpress之ChartControl的SeriesTemplate實例

    這篇文章主要介紹了DevExpress之ChartControl的SeriesTemplate用法實例,實現(xiàn)了餅狀Series百分比顯示的效果,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-10-10
  • C#實現(xiàn)簡單獲取及設(shè)置Session類

    C#實現(xiàn)簡單獲取及設(shè)置Session類

    這篇文章主要介紹了C#實現(xiàn)簡單獲取及設(shè)置Session類,涉及C#針對session的設(shè)置及獲取的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • C# 指針內(nèi)存控制Marshal內(nèi)存數(shù)據(jù)存儲原理分析

    C# 指針內(nèi)存控制Marshal內(nèi)存數(shù)據(jù)存儲原理分析

    這篇文章主要介紹了C# 指針 內(nèi)存控制 Marshal 內(nèi)存數(shù)據(jù)存儲原理分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C#使用NPOI讀取excel轉(zhuǎn)為DataSet

    C#使用NPOI讀取excel轉(zhuǎn)為DataSet

    這篇文章主要為大家詳細介紹了C#使用NPOI讀取excel轉(zhuǎn)為DataSet,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#凈化版WebApi框架的實現(xiàn)

    C#凈化版WebApi框架的實現(xiàn)

    這篇文章主要介紹了C#凈化版WebApi框架的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • C#使用whisper.net實現(xiàn)語音識別功能

    C#使用whisper.net實現(xiàn)語音識別功能

    這篇文章主要為大家詳細介紹了C#如何使用whisper.net實現(xiàn)語音識別功能,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以學(xué)習(xí)一下
    2023-11-11
  • C#從foreach語句中枚舉元素看數(shù)組詳解

    C#從foreach語句中枚舉元素看數(shù)組詳解

    這篇文章主要給大家介紹了關(guān)于C#從foreach語句中枚舉元素看數(shù)組的相關(guān)資料,文中介紹的非常詳細,對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。
    2017-05-05

最新評論