<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文看懂C# volatile 關(guān)鍵字

          共 3508字,需瀏覽 8分鐘

           ·

          2020-11-02 02:42

          要理解 C# 中的 volatile 關(guān)鍵字,就要先知道編譯器背后的一個基本優(yōu)化原理。比如對于下面這段代碼:

          public class Example
          {
          public int x;
          public void DoWork()
          {
          x = 5;
          var y = x + 10;
          Debug.WriteLine("x = " +x + ", y = " +y);
          }
          }

          在 Release 模式下,編譯器讀取 x = 5 后緊接著讀取 y = x + 10,在單線程思維模式下,編譯器會認(rèn)為 y 的值始終都是 15。所以編譯器會把 y = x + 10 優(yōu)化為 y = 15,避免每次讀取 y 都執(zhí)行一次 x + 5。但 x 字段的值可能在運(yùn)行時被其它的線程修改,我們拿到的 y 值并不是通過最新修改的 x 計算得來的,y 的值永遠(yuǎn)都是 15。

          也就是說,編譯器在 Release 模式下會對字段的訪問進(jìn)行優(yōu)化,它假定字段都是由單個線程訪問的,把與該字段相關(guān)的表達(dá)式運(yùn)算結(jié)果編譯成常量緩存起來,避免每次訪問都重復(fù)運(yùn)算。但這樣就可能導(dǎo)致其它線程修改了字段值而當(dāng)前線程卻讀取不到最新的字段值。為了防止編譯器這么做,你就要讓編譯器用多線程思維去解讀代碼。告訴編譯器字段的值可能會被其它線程修改,這種情況不要使用優(yōu)化策略。而要做到這一點,就需要使用 volatile 關(guān)鍵字。

          給類的字段添加 volatile 關(guān)鍵字,目的是告訴編譯器該字段的值可能會被多個獨(dú)立的線程改變,不要對該字段的訪問進(jìn)行優(yōu)化。

          使用 volatile 可以確保字段的值是可用的最新值,而且該值不會像非 volatile 字段值那樣受到緩存的影響。好的做法是將每個可能被多個線程使用的字段標(biāo)記為 volatile,以防止非預(yù)期的優(yōu)化行為。

          為了加深理解,我們來看一個實際的例子:

          public class Worker
          {
          private bool _shouldStop;

          public void DoWork()
          {
          bool work = false;
          // 注意:這里會被編譯器優(yōu)化為 while(true)
          while (!_shouldStop)
          {
          work = !work; // do sth.
          }
          Console.WriteLine("工作線程:正在終止...");
          }

          public void RequestStop()
          {
          _shouldStop = true;
          }
          }

          public class Program
          {
          public static void Main()
          {
          var worker = new Worker();

          Console.WriteLine("主線程:啟動工作線程...");
          var workerTask = Task.Run(worker.DoWork);

          // 等待 500 毫秒以確保工作線程已在執(zhí)行
          Thread.Sleep(500);

          Console.WriteLine("主線程:請求終止工作線程...");
          worker.RequestStop();

          // 待待工作線程執(zhí)行結(jié)束
          workerTask.Wait();
          //workerThread.Join();

          Console.WriteLine("主線程:工作線程已終止");
          }
          }

          在這個例子中,while (!_shouldStop) 會被編譯器優(yōu)化為 while(true)。我們可以看一下實際的運(yùn)行效果來驗證這一點。切換 Release 模式,按 Ctrl + F5 運(yùn)行程序,運(yùn)行效果始終如下:

          程序運(yùn)行后,雖然主線程在 500 毫秒后執(zhí)行 RequestStop() 方法修改了 _shouldStop 的值,但工作線程始終都獲取不到 _shouldStop 最新的值,也就永遠(yuǎn)都不會終止 while 循環(huán)。

          我們修改一下程序,對 _shouldStop 字段加上 volatile 關(guān)鍵字:

          public class Worker
          {
          private volatile bool _shouldStop;

          public void DoWork()
          {
          bool work = false;
          // 獲取的是最新的 _shouldStop 值
          while (!_shouldStop)
          {
          work = !work; // do sth.
          }
          Console.WriteLine("工作線程:正在終止...");
          }

          // ...(略)
          }

          此時在主線程調(diào)用 RequestStop() 方法后,工作線程便立即終止了,運(yùn)行效果如下圖所示:

          這說明加了 volatile 關(guān)鍵字后,程序可以實時讀取到字段的最新值。

          注意,一定要切換為 Release 模式運(yùn)行才能看到 volatile 發(fā)揮的作用,Debug 模式下即使添加了 volatile 關(guān)鍵字,編譯器也是不會執(zhí)行優(yōu)化的。

          當(dāng)然,并不是所有的類型都可以使用 volatile 關(guān)鍵字修飾的,常見的使用 volatile 的類型是這些簡單類型:sbyte, byte, short, ushort, int, uint, char, float 和 bool,其它的請查看參考鏈接。

          參考: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile

          回復(fù) 【關(guān)閉】學(xué)關(guān)
          回復(fù) 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復(fù) 【被刪】學(xué)
          回復(fù) 【訪客】學(xué)
          回復(fù) 【小程序】學(xué)獲取15套【入門+實戰(zhàn)+賺錢】小程序源碼
          回復(fù) 【python】學(xué)微獲取全套0基礎(chǔ)Python知識手冊
          回復(fù) 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
          回復(fù) 【加群】加入dotnet微信交流群

          終于GitHub App 已支持簡體中文!


          微信錢包“免費(fèi)提現(xiàn)”的方法來了!

          瀏覽 120
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲无码操逼 | 日韩无码高清电影 | 五月丁香激情综合 | 在线观看99.c | 激情综合视频在线 |