最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# Volatile的具體使用

 更新時間:2021年11月14日 10:04:49   作者:dotNet源計劃  
本文主要介紹了C# Volatile的具體使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

​1.Overview

經(jīng)常研究.NET源碼庫的小伙伴會經(jīng)常看到一個關鍵字volatile,那它在開發(fā)當中的作用是什么呢?

我們一起來看看官方文檔里是怎么描述的,如下:

volatile 關鍵字指示一個字段可以由多個同時執(zhí)行的線程修改。出于性能原因,編譯器,運行時系統(tǒng)甚至硬件都可能重新排列對存儲器位置的讀取和寫入。聲明為 volatile 的字段將從某些類型的優(yōu)化中排除。不確保從所有執(zhí)行線程整體來看時所有易失性寫入操作均按執(zhí)行順序排序。”

本文將圍繞這部分進行解讀。

聲明語法如下:

class VolatileTest
{
   public volatile int sharedStorage;
   
   public void Test(int i)
  {
       sharedStorage = i;
  }
}

2.Detail

我們先了解一下前置知識點。

(1)在CLR中將對sbyte、byte、short、ushort、int、uint、charfloatbool。以及引用類型保證讀寫時原子性的(long、double不是原子性讀寫)變量中的所有字節(jié)都是一次性寫入或讀取的。

(2)Framework Class Library(FCL) 保證所有靜態(tài)方法都是線程安全的。這意味著假如兩個線程同時調用一個靜態(tài)方法,不會有數(shù)據(jù)被損壞。為什么?

public static string Print(String str)
{
   string val = "";
   val += str;
   return val;
}

因為靜態(tài)方法內(nèi)聲明的變量,每個線程調用時都會新創(chuàng)建一份,而不會共用一個存儲單元。比如這里的val每個線程都會創(chuàng)建自己的一份,因此不會有線程安全問題。注意:靜態(tài)變量,由于是在類加載時占用一個存儲區(qū)每個線程都是共用這個存儲區(qū)的,所以如果在靜態(tài)方法里使用了靜態(tài)變量;這就會有線程安全問題。

(3)內(nèi)存、CPU緩存(注:下列為簡述內(nèi)容,實際上不僅如此)

CPU緩存,CPU集成的緩存。

內(nèi)存,內(nèi)存條硬件提供的存儲空間。

我們繼續(xù)回到主要內(nèi)容上,用下面的若干代碼示例來表達volatile的作用。

public class Program
{
       public static int bookNum = 0;

       public static void Main(string[] args)
      {
           Console.WriteLine("juster書的數(shù)量:" + bookNum);

           Thread juster = new Thread(() =>
          {
               Console.WriteLine("juster沒帶書,等待家長送書到學校...");

               while (bookNum == 0) {}

               Console.WriteLine("juster拿到書,開始上課聽講。");
          });
           juster.Name = nameof(juster);
           juster.Start();

           Thread parent = new Thread(() =>
          {
               Console.WriteLine("parent在屋里找書中...");

               Thread.Sleep(2000);

               Console.WriteLine("parent找到了書之后,送往學校...");

               SendBook();
          });
           parent.Name = nameof(parent);
           parent.Start();
      }

       public static void SendBook()
      {
           bookNum = 1;
      }
}

代碼執(zhí)行輸出如下:

這時候詭異的來了,按照正常的代碼執(zhí)行邏輯不難看出當parent線程執(zhí)行Sendbook()的時候juster應該就能拿到書上課了。但是這里juster卻一直沒有拿到是為什么呢?

心細的小伙伴應該觀察到了這里的運行模式是Release,眾所周知Release是.Net的發(fā)布版本執(zhí)行效率會比Debug版本要高。

為什么Release版本效率高呢?怎么得來的?下面這段代碼來解釋:

上面這張反編譯的圖不難看出,10*10-100這段代碼直接編譯成0了。這種現(xiàn)象是因為Release編譯的時候編譯器會對代碼進行‘優(yōu)化'。這段是最直觀能看到的‘優(yōu)化'效果,其實C#編譯器將你的代碼轉換成中間語言(IL)。然后,JIT將IL轉換成本機CPU指令。此外,C#編譯器、JIT編譯器,甚至CPU本身都可能優(yōu)化你的代碼。

但是實際上在上述代碼中count的值始終為0;所以循環(huán)永遠不會執(zhí)行,沒有必要編譯循環(huán)內(nèi)的代碼在編譯后會被‘優(yōu)化'。說了這么多,只是為了給大伙證明Release編譯這一層會存在‘優(yōu)化';接下來繼續(xù)回到volatile上。

說到這里,如何解決各種‘優(yōu)化'帶來的問題呢?這時候只需要在booknum前面加上volatile關鍵字修飾即可。

public class Program
{
       public static volatile int bookNum = 0;

       public static void Main(string[] args)
      {
           Console.WriteLine("juster書的數(shù)量:" + bookNum);

           Thread juster = new Thread(() =>
          {
               Console.WriteLine("juster沒帶書,等待家長送書到學校...");

               while (bookNum == 0) { }

               Console.WriteLine("juster拿到書,開始上課聽講。");
          });
           juster.Name = nameof(juster);
           juster.Start();


           Thread parent = new Thread(() =>
          {
               Console.WriteLine("parent在屋里找書中...");

               Thread.Sleep(2000);

               Console.WriteLine("parent找到了書之后,送往學校...");

               SendBook();
          });
           parent.Name = nameof(parent);
           parent.Start();
      }

       public static void SendBook()
      {
           bookNum = 1;
      }
}

在被各種優(yōu)化之后,booknum因為是值類型在每個線程訪問時會發(fā)生復制且又是在靜態(tài)方法中被修改。所以每個線程都會復制booknum的值到當前線程上下文中緩存起來。這樣就導致了parent線程修改了booknum的值juster線程看不到的情況。這個時候就需要用volatile關鍵字告訴編譯器不需要這樣的優(yōu)化,表示用volatile定義的變量會被改變,每次都必須從內(nèi)存中讀取,而不能把他放在CPU cache或寄存器中重復使用。最后booknum會在運行的過程中修改值且其他線程能‘共享訪問'達到最終的效果。

3.Conclusion

Part1

volatile 關鍵字可應用于以下類型的字段:

  • 引用類型。
  • 指針類型(在不安全的上下文中)。請注意,雖然指針本身可以是可變的,但是它指向的對象不能是可變的。換句話說,不能聲明“指向可變對象的指針”。
  • 簡單類型,如 sbyte、byte、short、ushort、intuint、charfloatbool。
  • 具有以下基本類型之一的 enum 類型:byte、sbyte、short、ushortintuint。
  • 已知為引用類型的泛型類型參數(shù)。
  • IntPtr 和 UIntPtr。

其他類型(包括 doublelong)無法標記為 volatile,因為對這些類型的字段的讀取和寫入不能保證是原子的。若要保護對這些類型字段的多線程訪問,請使用 Interlocked 類成員或使用 lock 語句保護訪問權限。

volatile 關鍵字只能應用于 classstruct 的字段。不能將局部變量聲明為 volatile。

Part2

volatile并不能用來做線程同步,它的主要作用時為了讓多個線程之間能看到被修改過后最新的值。

Part3

C#不支持以傳遞引用的方式將volatile字段傳給方法。

int.TryParse("123", out x);

Part4

除了禁止編譯優(yōu)化,還有同步到內(nèi)存中因為CPU每個核心都有自己Cache所以需要同步到內(nèi)存中方便其他核心使用。

Part5

看完本文也能解開小白時期的疑惑,為什么我寫代碼編譯成release版本之后就不能運行報錯的奇特現(xiàn)象了。

Part6

volatile 牽扯到的相關知識點和原理遠遠不止這些。

4.Reference

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/volatile?WT.mc_id=WDIT-MVP-5004326

到此這篇關于C# Volatile的具體使用的文章就介紹到這了,更多相關C# Volatile內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 用C#將圖片保存至Oracle BLOB字段中的方法

    用C#將圖片保存至Oracle BLOB字段中的方法

    這篇文章主要介紹了用C#將圖片保存至Oracle BLOB字段中的方法, 依靠ImageViewer庫進行操作,需要的朋友可以參考下
    2015-07-07
  • C++實現(xiàn)日期類的示例詳解

    C++實現(xiàn)日期類的示例詳解

    這篇文章主要為大家詳細介紹了四個C++常用的日期類的實現(xiàn),文中的示例代碼講解詳細,對我們學習C++有一定的幫助,需要的可以參考一下
    2023-02-02
  • 如何在C#中使用JIEBA.NET實現(xiàn)中文分詞

    如何在C#中使用JIEBA.NET實現(xiàn)中文分詞

    JIEBA 是一款優(yōu)秀的中文分詞工具,為了方便 .NET 開發(fā)者使用,JIEBA.NET 作為一個封裝了 JIEBA 的 C# 庫,提供了類似的分詞功能,下面我們來看看它的具體操作吧
    2025-03-03
  • C#實現(xiàn)拼圖游戲

    C#實現(xiàn)拼圖游戲

    這篇文章主要為大家詳細介紹了C#實現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • c#制作屏幕保護程序步驟(字幕屏保)

    c#制作屏幕保護程序步驟(字幕屏保)

    本文介紹使用C#制作屏幕保護的方法,這個屏幕保護就是仿效視窗系統(tǒng)自帶的字幕屏保。下面是用C#如何編寫屏幕保護的整個過程
    2014-01-01
  • 使用NOPI讀取Word、Excel文檔內(nèi)容

    使用NOPI讀取Word、Excel文檔內(nèi)容

    這篇文章主要為大家詳細介紹了使用NOPI讀取Word、Excel文檔內(nèi)容的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • C#關鍵字async/await用法

    C#關鍵字async/await用法

    在本篇文章里小編給大家整理的是關于C#關鍵字async/await用法及相關實例,需要的朋友們學習下。
    2019-12-12
  • C#控制臺程序的開發(fā)與打包為一個exe文件實例詳解

    C#控制臺程序的開發(fā)與打包為一個exe文件實例詳解

    所謂控制臺程序,就是沒有界面,運行程序后只有一個黑色的類似cmd窗口,通過這個窗口進行交互,下面這篇文章主要給大家介紹了關于C#控制臺程序的開發(fā)與打包為一個exe文件的相關資料,需要的朋友可以參考下
    2023-05-05
  • C# .NET 中的緩存實現(xiàn)詳情

    C# .NET 中的緩存實現(xiàn)詳情

    軟件開發(fā)中最常用的模式之一是 緩存 ,其包括進程內(nèi)緩存、持久性進程內(nèi)緩存和分布式緩存,本文我們將主要介紹進程內(nèi)緩存,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • 使用JsonConverter處理上傳文件的路徑問題

    使用JsonConverter處理上傳文件的路徑問題

    我們上傳一個文件,把文件保存到服務器上,會有一個明確的物理路徑,由于需要從前端訪問這個文件,還需要web服務器中的一個虛擬路徑,我們可以使用JsonConverter 來自動處理一下,這篇文章主要介紹了使用JsonConverter處理上傳文件的路徑,需要的朋友可以參考下
    2022-12-12

最新評論

穆棱市| 封丘县| 孙吴县| 黔西县| 容城县| 海口市| 鄢陵县| 芜湖市| 高尔夫| 鹿邑县| 阳高县| 昌宁县| 潢川县| 建瓯市| 叶城县| 洛阳市| 漳州市| 顺义区| 滁州市| 富宁县| 莱西市| 黔南| 农安县| 高州市| 古交市| 安图县| 屏南县| 宁津县| 义乌市| 龙山县| 南漳县| 正阳县| 汪清县| 紫云| 阿坝县| 丘北县| 怀远县| 海淀区| 丰顺县| 察哈| 菏泽市|