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

首頁 > 編程 > C# > 正文

深入多線程之:內存柵欄與volatile關鍵字的使用分析

2020-01-24 03:19:36
字體:
來源:轉載
供稿:網友

以前我們說過在一些簡單的例子中,比如為一個字段賦值或遞增該字段,我們需要對線程進行同步,
雖然lock可以滿足我們的需要,但是一個競爭鎖一定會導致阻塞,然后忍受線程上下文切換和調度的開銷,在一些高并發和性能比較關鍵的地方,這些是不能忍受的。
.net framework 提供了非阻塞同步構造,為一些簡單的操作提高了性能,它甚至都沒有阻塞,暫停,和等待線程。

Memory Barriers and Volatility (內存柵欄和易失字段 )
考慮下下面的代碼:

復制代碼 代碼如下:

int _answer;
        bool _complete;
        void A()
        {
            _answer = 123;
            _complete = true;
        }
        void B()
        {
            if (_complete)
                Console.WriteLine(_answer);
        }

如果方法A和B都在不同的線程下并發的執行,方法B可能輸出 “0” 嗎?

回答是“yes”,基于以下原因:
    編譯器,clr 或 cpu 可能會為了性能而重新為程序的指令進行排序,例如可能會將方法A中的兩句代碼的順序進行調整。
    編譯器,clr 或 cpu 可能會為變量的賦值采用緩存策略,這樣這些變量就不會立即對其他變量可見了,例如方法A中的變量賦值,不會立即刷新到內存中,變量B看到的變量并不是最新的值。

C# 和運行時非常小心的保證這些優化策略不會影響正常的單線程的代碼和在多線程環境下加鎖的代碼。
除此之外,你必須顯示的通過創建內存屏障(Memory fences) 來限制指令重新排序和讀寫緩存對程序造成的影響。

Full fences:

最簡單的完全柵欄的方法莫過于使用Thread.MemoryBarrier方法了。

以下是msdn的解釋:
Thread.MemoryBarrier: 按如下方式同步內存訪問:執行當前線程的處理器在對指令重新排序時,不能采用先執行 MemoryBarrier 調用之后的內存訪問,再執行 MemoryBarrier 調用之前的內存訪問的方式。
按照我個人的理解:就是寫完數據之后,調用MemoryBarrier,數據就會立即刷新,另外在讀取數據之前調用MemoryBarrier可以確保讀取的數據是最新的,并且處理器對MemoryBarrier的優化小心處理。

復制代碼 代碼如下:

int _answer;
        bool _complete;
        void A()
        {
            _answer = 123;
            Thread.MemoryBarrier(); //在寫完之后,創建內存柵欄
            _complete = true;
            Thread.MemoryBarrier();//在寫完之后,創建內存柵欄      
       }
        void B()
        {
            Thread.MemoryBarrier();//在讀取之前,創建內存柵欄
            if (_complete)
            {
                Thread.MemoryBarrier();//在讀取之前,創建內存柵欄
                Console.WriteLine(_answer);
            }
        }

一個完全的柵欄在現代桌面應用程序中,大于需要花費10納秒。
下面的一些構造都隱式的生成完全柵欄。

    C# Lock 語句(Monitor.Enter / Monitor.Exit)
    在Interlocked類的所有方法。
    使用線程池的異步回調,包括異步的委托,APM 回調,和 Task continuations.
    在一個信號構造中的發送(Settings)和等待(waiting)

你不需要對每一個變量的讀寫都使用完全柵欄,假設你有三個answer 字段,我們仍然可以使用4個柵欄。例如:

復制代碼 代碼如下:

int _answer1, _answer2, _answer3;
        bool _complete;
        void A()
        {
            _answer1 = 1; _answer2 = 2; _answer3 = 3;
            Thread.MemoryBarrier(); //在寫完之后,創建內存柵欄
            _complete = true;
            Thread.MemoryBarrier(); //在寫完之后,創建內存柵欄
        }
        void B()
        {
            Thread.MemoryBarrier(); //在讀取之前,創建內存柵欄
            if (_complete)
            {
                Thread.MemoryBarrier(); //在讀取之前,創建內存柵欄
                Console.WriteLine(_answer1 + _answer2 + _answer3);
            }
        }

我們真的需要lock 和內存柵欄嗎?
在一個共享可寫的字段上不使用lock 或者柵欄 就是在自找麻煩,在msdn上有很多關于這方面的主題。
考慮下下面的代碼:
復制代碼 代碼如下:

public static void Main()
        {
            bool complete = false;
            var t = new Thread(() =>
                {
                    bool toggle = false;
                    while (!complete) toggle = !toggle;
                });
            t.Start();
            Thread.Sleep(1000);
            complete = true;
            t.Join();
        }

如果你在Visual Studio中選擇發布模式,生成該應用程序,那么如果你直接運行應用程序,程序都不會中止。
因為CPU 寄存器把 complete 變量的值給緩存了。在寄存器中,complete永遠都是false。
通過在while循環中插入Thread.MemoryBarrier,或者是在讀取complete的時候加鎖 都可以解決這個問題。

volatile 關鍵字
為_complete字段加上volatile關鍵字也可以解決這個問題。
volatile bool _complete.

Volatile關鍵字會指導編譯器自動的為讀寫字段加屏障.以下是msdn的解釋:
volatile 關鍵字指示一個字段可以由多個同時執行的線程修改。聲明為 volatile 的字段不受編譯器優化(假定由單個線程訪問)的限制。這樣可以確保該字段在任何時間呈現的都是最新的值。

使用volatile字段可以被總結成下表:

第一條指令

第二條指令

可以被交換嗎?

Read

Read

No

Read

Write

No

Write

Write

No(CLR會確保寫和寫的操作不被交換,甚至不使用volatile關鍵字)

Write

Read

Yes!


注意到應用volatile關鍵字,并不能保證寫后面跟讀的操作不被交換,這有可能會造成莫名其妙的問題。例如:
復制代碼 代碼如下:

volatile int x, y;
        void Test1()
        {
            x = 1;      //Volatile write
            int a = y;  //Volatile Read
        }

        void Test2()
        {
            y = 1;      //Volatile write
            int b = x;  //Volatile Read
        }


如果Test1和Test2在不同的線程中并發執行,有可能a 和b 字段的值都是0,(盡管在x和y上應用了volatile 關鍵字)

這是一個避免使用volatile關鍵字的好例子,甚至假設你徹底的明白了這段代碼,是不是其他在你的代碼上工作的人也全部明白呢?。

在Test1 和Test2方法中使用完全柵欄或者是lock都可以解決這個問題,

還有一個不使用volatile關鍵字的原因是性能問題,因為每次讀寫都創建了內存柵欄,例如

復制代碼 代碼如下:

volatile m_amount
m_amount  = m_amount + m_amount.

Volatile 關鍵字不支持引用傳遞的參數,和局部變量。在這樣的場景下,你必須使用

VolatileRead和VolatileWrite方法。例如

復制代碼 代碼如下:

volatile int m_amount;
Boolean success =int32.TryParse(“123”,out m_amount);
//生成如下警告信息:
//cs0420:對volatile字段的引用不被視為volatile.


VolatileRead 和VolatileWrite

從技術上講,Thread類的靜態方法VolatileRead和VolatileWrite在讀取一個 變量上和volatile 關鍵字的作用一致。

他們的實現是一樣是低效率的,盡管事實上他們都創建了內存柵欄。下面是他們在integer類型上的實現。

復制代碼 代碼如下:

public static void VolatileWrite(ref int address, int value)
        {
            Thread.MemoryBarrier(); address = value;
        }

        public static int VolatileRead(ref int address)
        {
            int num = address; Thread.MemoryBarrier(); return num;
        }


你可以看到如果你在調用VolatileWrite之后調用VolatileRead,在中間沒有柵欄會被創建,這同樣會導致我們上面講到寫之后再讀順序可能變換的問題。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国内精品久久久久久久| 国产日韩中文字幕| 亚洲美女又黄又爽在线观看| 欧美精品成人91久久久久久久| 久久免费视频在线| 亚洲区免费影片| 国产亚洲视频在线观看| 日韩一区二区三区国产| 久久久久久亚洲| 欧美激情在线视频二区| 亚洲天堂男人天堂女人天堂| 国产精品视频一区二区高潮| 欧美激情区在线播放| 蜜臀久久99精品久久久无需会员| 91精品国产高清久久久久久久久| 欧美区二区三区| 欧美尺度大的性做爰视频| 亚洲欧美国产一本综合首页| 精品毛片网大全| 国产欧美日韩视频| 77777少妇光屁股久久一区| 国产日本欧美在线观看| 精品综合久久久久久97| 亚洲精品免费av| 精品电影在线观看| 2020久久国产精品| 日韩精品视频免费在线观看| 91影院在线免费观看视频| 国产精品吹潮在线观看| 国产视频在线一区二区| 亚洲精品福利在线| 日韩在线观看成人| 在线观看日韩欧美| 精品欧美国产一区二区三区| 亚洲色在线视频| 亚洲视频日韩精品| 性欧美暴力猛交69hd| 国产精品亚洲自拍| 欧美二区乱c黑人| 亚洲精品国产拍免费91在线| 色婷婷av一区二区三区久久| 国产精品jvid在线观看蜜臀| 久久久久久久网站| 亚洲国产精品福利| 精品亚洲男同gayvideo网站| 欧美刺激性大交免费视频| 久国内精品在线| 久久久国产精彩视频美女艺术照福利| 欧美国产第二页| 日韩电影免费在线观看| 日本成人精品在线| 91精品久久久久久久久久久久久久| 日韩av在线一区二区| 亚洲欧美另类人妖| 欧美亚洲激情视频| 欧美激情综合色综合啪啪五月| 亚洲成年人在线播放| 欧美精品手机在线| 激情懂色av一区av二区av| 超碰精品一区二区三区乱码| 日韩一区二区在线视频| 精品二区三区线观看| 日韩h在线观看| 国内精品久久久久影院 日本资源| 亚洲欧洲日产国码av系列天堂| 欧美激情精品久久久久久久变态| 亚洲精品国产品国语在线| 91免费看国产| 中文字幕欧美日韩精品| 国产一区二区三区中文| 国产欧美婷婷中文| 日本精品中文字幕| 欧美日韩激情小视频| 久久好看免费视频| www欧美日韩| 国产精品久久久久久久久久久久久| 国产精品亚洲网站| 久久中文字幕视频| 日韩精品免费在线| 高清欧美一区二区三区| 国产精品一区二区av影院萌芽| 日韩免费av一区二区| 日韩欧美成人精品| 国产高清视频一区三区| 在线观看欧美日韩国产| 亚洲精品99久久久久| 色狠狠av一区二区三区香蕉蜜桃| 亚洲日本成人女熟在线观看| 国产欧美日韩精品专区| 国产一区二区三区在线观看视频| 欧美性xxxxxxxxx| 欧美一乱一性一交一视频| 成人av电影天堂| 国产一区二区三区视频免费| 成人在线视频网站| 久久久精品999| 日韩在线观看免费| 欧美日韩在线观看视频小说| 亚洲欧美日韩国产中文专区| 国产热re99久久6国产精品| 国产成人精品av| 一区二区国产精品视频| 性欧美xxxx视频在线观看| 亚洲一区二区免费| 欧美日韩国产在线看| 久久天天躁狠狠躁夜夜爽蜜月| 色小说视频一区| 欧美日韩国产丝袜另类| 国产精品中文字幕久久久| 性欧美办公室18xxxxhd| 亚洲男人天堂视频| 亚洲精品丝袜日韩| 96sao精品视频在线观看| 日韩视频永久免费观看| 久久久久久久电影一区| 97精品国产97久久久久久| 欧美激情精品久久久久久| 亚洲影院污污.| 国产精品视频色| 欧美精品做受xxx性少妇| 亚洲欧美一区二区三区在线| 中文字幕久热精品视频在线| 欧美电影《睫毛膏》| 国产精品成人久久久久| 色婷婷av一区二区三区在线观看| 久久久av一区| 久久久久久九九九| 久久精品电影网站| 欧美小视频在线| 狠狠色狠狠色综合日日五| 国产精品视频自在线| 欧美乱妇高清无乱码| 国产精品久久久亚洲| 久久夜色撩人精品| 国产精品美女999| 色噜噜国产精品视频一区二区| 欧美激情视频在线观看| 精品国产91久久久久久老师| 91免费版网站入口| 日韩av影院在线观看| 久久影院中文字幕| 欧美在线视频免费| 欧美成人一区二区三区电影| 亚洲一区二区福利| 亚洲视频一区二区| 91国自产精品中文字幕亚洲| 日韩成人在线网站| 国内精品400部情侣激情| 亚洲新中文字幕| 最近2019好看的中文字幕免费| 久久亚洲成人精品| 成人免费视频在线观看超级碰| 亚洲人高潮女人毛茸茸| 欧美黑人极品猛少妇色xxxxx| 国产成人亚洲精品| 国产69久久精品成人看| 国产精品青草久久久久福利99| 亚洲欧美国产一区二区三区| 欧美成人午夜激情| 国产精品久久久精品| 国产精品九九九| 国产va免费精品高清在线观看| 国产人妖伪娘一区91| 国产精品视频资源|