亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

.NET中保證線程安全的高級方法Interlocked類使用介紹

2020-01-24 02:39:54
字體:
來源:轉載
供稿:網友

說到線程安全,不要一下子就想到加鎖,尤其是可能會調用頻繁或者是要求高性能的場合。

對于性能要求不高或者同步的對象數量不多的時候,加鎖是一個比較簡單而且易于實現的選擇。比方說.NET提供的一些基礎類庫,比如線程安全的堆棧和隊列,如果使用加鎖的方式那么會使性能大打折扣(速度可能會降低好幾個數量級),而且如果設計得不好的話還有可能發生死鎖。

現在通過查看微軟的源代碼來學習一些不直接lock(等價于Monitor類)的線程同步技巧吧。

這里我們主要用的是Interlocked類,這個類按照M$的描述,是“為多個線程共享的變量提供原子操作”,當然這個類是一個靜態類。這個類的源代碼看不到,因為是調用的CLR內部的方法,不過基本思想應該是通過硬件原語try and set來實現的。

該類提供的Add、Increment、Decrement能夠完成簡單的原子操作。

假如我們要提供一個計數器,每訪問一次就遞增地返回一個新的數值用于計數。在多線程環境下,s++這一條語句不是線程安全的。因為執行這個語句要經過:移到寄存器(讀取)、運算、寫入這幾個步驟,在任何時候都可能會切換到其他線程,這樣子s被多個線程訪問值可能會在切換的過程中丟失。有了Interlocked提供的這幾個原子操作的方法,就不用自己去加鎖實現這些簡單的運算了。由于是使用的硬件原語,其效率自然也比加鎖高得多。

但是大多數情況下,問題并沒有執行相加相減運算那么簡單,這時如果不想用鎖的話就要想想辦法了。

以微軟的ConcurrentStack提供的線程安全的堆棧為例,分析一下如何實現如果往棧頭添加數據。

m_head是指向堆頂的指針,在定義的時候由于是多線程訪問的,所以要加上volatile修飾符:

復制代碼 代碼如下:

private volatile Node m_head;

如果是單線程的,那么入棧語句就是下面這個樣子:

復制代碼 代碼如下:

1.    Node newNode = new Node(item);
2.    newNode.m_next = m_head;
3.    m_head = newNode;

假如有兩個線程并發訪問入棧方法的話,那么可能會產生如下情況:第一個線程執行完第二條語句被打斷,第二個線程執行到第二條語句又切換回第一個線程,兩個線程執行完后有一個入棧的元素就不見了。那么如何實現線程安全呢?M$的代碼是這樣寫的:

復制代碼 代碼如下:

Node newNode = new Node(item);
newNode.m_next = m_head;
if (Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next)
{
    return;
}

// If we failed, go to the slow path and loop around until we succeed.
PushCore(newNode, newNode);


首先,Interlocked.CompareExchange比較兩個元素是否相等,并根據比較的結果替換其中一個元素,返回結果始終是第一個元素的原值。這個方法是原子操作。

那么這段代碼首先設置newNode的下一節點為堆棧頂部的元素,接下來CompareExchange,判斷棧頂元素有沒有被修改過。假如此時沒有另一個線程修改棧頂元素,那么m_head還是原來的值(上一條語句設置的新棧頂的下一個元素),此時就可以安全地把棧頂指針指向新元素,操作完成(return)。注意CompareExchange是原子操作的,所以在這期間棧頂元素不可能再被修改。

如果比較結果不相等,那么說明棧頂元素已經被其他線程修改了(此時返回值就是被修改后的棧頂,和上一條語句設置m_next不一樣),這樣CompareExchange就不會修改m_head,說明入棧不成功,執行PushCore方法。


這個東東的代碼如下:

復制代碼 代碼如下:

        private void PushCore(Node head, Node tail)
        {
            SpinWait spin = new SpinWait();

            // Keep trying to CAS the exising head with the new node until we succeed.
            do
            {
                spin.SpinOnce();
                // Reread the head and link our new node.
                tail.m_next = m_head;
            }
            while (Interlocked.CompareExchange(
                ref m_head, head, tail.m_next) != tail.m_next);

#if !FEATURE_PAL && !FEATURE_CORECLR
            if (CDSCollectionETWBCLProvider.Log.IsEnabled())
            {
                CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPushFailed(spin.Count);
            }
#endif //!FEATURE_PAL && !FEATURE_CORECLR
        }


可以看到其邏輯還是和上面那個一樣,只是加了一個循環直到操作完成。在這期間使用了一個SpinWait對象和SpinOnce方法,那么我們又要了解一下這是干嘛的。

關于SpinWait對象,M$的說明是:System.Threading.SpinWait 是一個輕量同步類型,可以在低級別方案中使用它來避免內核事件所需的高開銷的上下文切換和內核轉換。

關于它的說明還有一堆,你可以參考這里。如果不想看那么多,那么只需了解它的使用場合是在資源不會被占用很長時間的時候進行等待,以用戶模式自旋以避免高額的開銷。

SpinOnce的說明很簡單,就是執行單一自旋,可以理解為等待一個很短的時間??偟膩碚f,當自旋此時達到5次時,會切換到同一處理器上的另一個線程,當達到20次時,會調用Thread的Sleep方法阻塞當前線程,此時可以切換到其他同優先級或更高優先級的線程上去。

這樣,就可以避免加鎖(lock free)的高昂代價來實現線程的同步。

但是有的時候我們不能保證線程安全。比如堆棧的Count屬性,在程序調用這個屬性后,我們并不能保證這個屬性返回的時候是正確的,在返回到應用程序的線程前元素數量是有可能變化的,因此我們也就只能保證我們的返回值曾經正確。

不過顯而易見,這是可以接受的。對于開發者來說,假如我們要訪問一個多線程字典(ConcurrentDictionary)中的指定元素,我們不應該是先判斷是否為空再取元素(因為元素可能在這兩步操作之間被刪掉),而是應該使用TryGetValue這種保證線程安全的方法來進行操作。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久久久91| 欧美黑人极品猛少妇色xxxxx| 性欧美激情精品| 欧美最猛黑人xxxx黑人猛叫黄| 国产精品美女视频网站| 久久97精品久久久久久久不卡| 精品国产欧美一区二区五十路| 亚洲精品自在久久| 欧美高清性猛交| 国产亚洲人成网站在线观看| 日本精品视频在线| 一本色道久久综合狠狠躁篇的优点| 国产午夜一区二区| 亚洲伦理中文字幕| 日韩中文字幕网站| 97视频在线观看免费| 国产精品第三页| 亚洲自拍偷拍福利| 精品视频在线观看日韩| 51ⅴ精品国产91久久久久久| 久久久久久久香蕉网| 欧美高清性猛交| 欧美性开放视频| 色偷偷偷亚洲综合网另类| 久国内精品在线| 欧美壮男野外gaytube| 永久555www成人免费| 亚洲综合成人婷婷小说| 国产日韩欧美综合| 亚洲第一精品自拍| 国产精品电影在线观看| 久久国产精品免费视频| 久久综合免费视频| 欧美激情亚洲精品| 91亚洲国产成人久久精品网站| 久久精品视频va| 国内精品小视频在线观看| 亚洲精品国产精品国自产观看浪潮| 91麻豆桃色免费看| 国产免费亚洲高清| 亚洲一区美女视频在线观看免费| 视频直播国产精品| 精品在线欧美视频| 2019国产精品自在线拍国产不卡| 国产精品丝袜一区二区三区| 亚洲电影av在线| 国产精品自拍小视频| 欧美午夜激情小视频| 亚洲国产成人精品久久| 日韩美女av在线免费观看| 亚洲欧美一区二区精品久久久| 亚洲人成77777在线观看网| 国产91免费看片| 91免费国产网站| 久久99精品久久久久久噜噜| 久久久国产精品视频| 色噜噜狠狠狠综合曰曰曰88av| 海角国产乱辈乱精品视频| 亚洲第一视频网站| 久久琪琪电影院| 国产精品自拍视频| 国产日韩精品一区二区| 亚洲欧美日韩中文在线| 欧美专区福利在线| 青青久久aⅴ北条麻妃| 亚洲电影免费观看高清| 国产在线拍揄自揄视频不卡99| 欧美日韩国产二区| 亚洲欧洲av一区二区| 国产一区二区在线免费| 91丝袜美腿美女视频网站| 精品毛片网大全| 97视频在线观看视频免费视频| 国产91色在线免费| 日韩成人免费视频| 欧美性猛交xxxx免费看| 92裸体在线视频网站| 九九热精品视频在线播放| 一区二区三区高清国产| 91影院在线免费观看视频| 在线视频日韩精品| 久久久精品一区二区三区| 久久色免费在线视频| 欧美成人精品在线观看| 国产福利精品视频| 欧美高清理论片| 日韩av免费在线| 欧美日韩在线观看视频小说| 亚洲人成网站免费播放| 久久久亚洲成人| 国产精品草莓在线免费观看| 91精品啪在线观看麻豆免费| 欧美日韩人人澡狠狠躁视频| 欧美久久精品午夜青青大伊人| 在线观看日韩专区| 成人激情视频在线观看| 久久久av电影| 欧美在线免费视频| 69av在线视频| 青青草国产精品一区二区| 日本精品一区二区三区在线播放视频| 精品在线小视频| 欧美激情亚洲精品| 国产精品一久久香蕉国产线看观看| 亚洲视频自拍偷拍| 亚洲精品日韩激情在线电影| 国产精品成人v| 久久久国产精品x99av| 国产久一一精品| 亚洲一品av免费观看| 一本色道久久综合狠狠躁篇的优点| 日韩精品欧美激情| 国产精品久久久久福利| 亚洲人成毛片在线播放| 国产视频福利一区| 国产成人高潮免费观看精品| 国产精品一区电影| 日韩电影在线观看免费| 亚洲精品欧美极品| 大伊人狠狠躁夜夜躁av一区| 国内精品模特av私拍在线观看| 超碰精品一区二区三区乱码| 韩国三级日本三级少妇99| 亚洲综合中文字幕在线观看| 国产精品男人爽免费视频1| 色爱av美腿丝袜综合粉嫩av| 国产精品福利小视频| 国产亚洲欧洲在线| 成人黄色免费片| 精品日韩视频在线观看| 亚洲美女精品久久| 精品国产乱码久久久久久虫虫漫画| 日本高清+成人网在线观看| 亚洲午夜未删减在线观看| 欧美日韩中文字幕在线| 欧美视频一区二区三区…| 亚洲第一页中文字幕| 在线视频一区二区| 91深夜福利视频| 久久香蕉频线观| 精品久久久久久久大神国产| 欧美精品18videos性欧美| 夜夜躁日日躁狠狠久久88av| 一本色道久久88精品综合| 久久久精品亚洲| 亚洲美女中文字幕| 亚洲黄在线观看| 中文字幕欧美精品日韩中文字幕| 亚洲男子天堂网| 久久久免费观看| 亚洲一区999| 亚洲综合日韩在线| 伊人久久久久久久久久久久久| 亚洲欧美国产高清va在线播| 亚洲美女av在线播放| 日韩va亚洲va欧洲va国产| 国产www精品| 综合网日日天干夜夜久久| 亚洲第一网中文字幕| 久久99国产精品自在自在app| 久久精品国产一区二区电影| 91精品国产91久久久久久最新| 7777免费精品视频| 狠狠爱在线视频一区|