您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關c# 實現volatile 關鍵字的拾遺補漏,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
要理解 C# 中的 volatile
關鍵字,就要先知道編譯器背后的一個基本優化原理。比如對于下面這段代碼:
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
,在單線程思維模式下,編譯器會認為 y
的值始終都是 15
。所以編譯器會把 y = x + 10
優化為 y = 15
,避免每次讀取 y
都執行一次 x + 5
。但 x
字段的值可能在運行時被其它的線程修改,我們拿到的 y
值并不是通過最新修改的 x
計算得來的,y
的值永遠都是 15
。
也就是說,編譯器在 Release 模式下會對字段的訪問進行優化,它假定字段都是由單個線程訪問的,把與該字段相關的表達式運算結果編譯成常量緩存起來,避免每次訪問都重復運算。但這樣就可能導致其它線程修改了字段值而當前線程卻讀取不到最新的字段值。為了防止編譯器這么做,你就要讓編譯器用多線程思維去解讀代碼。告訴編譯器字段的值可能會被其它線程修改,這種情況不要使用優化策略。而要做到這一點,就需要使用 volatile
關鍵字。
給類的字段添加 volatile
關鍵字,目的是告訴編譯器該字段的值可能會被多個獨立的線程改變,不要對該字段的訪問進行優化。
使用 volatile
可以確保字段的值是可用的最新值,而且該值不會像非 volatile
字段值那樣受到緩存的影響。好的做法是將每個可能被多個線程使用的字段標記為 volatile
,以防止非預期的優化行為。
為了加深理解,我們來看一個實際的例子:
public class Worker { private bool _shouldStop; public void DoWork() { bool work = false; // 注意:這里會被編譯器優化為 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 毫秒以確保工作線程已在執行 Thread.Sleep(500); Console.WriteLine("主線程:請求終止工作線程..."); worker.RequestStop(); // 待待工作線程執行結束 workerTask.Wait(); //workerThread.Join(); Console.WriteLine("主線程:工作線程已終止"); } }
在這個例子中,while (!_shouldStop)
會被編譯器優化為 while(true)
。我們可以看一下實際的運行效果來驗證這一點。切換 Release 模式,按 Ctrl + F5 運行程序,運行效果始終如下:
程序運行后,雖然主線程在 500 毫秒后執行 RequestStop()
方法修改了 _shouldStop
的值,但工作線程始終都獲取不到 _shouldStop
最新的值,也就永遠都不會終止 while
循環。
我們修改一下程序,對 _shouldStop
字段加上 volatile
關鍵字:
public class Worker { private volatile bool _shouldStop; public void DoWork() { bool work = false; // 獲取的是最新的 _shouldStop 值 while (!_shouldStop) { work = !work; // do sth. } Console.WriteLine("工作線程:正在終止..."); } // ...(略) }
此時在主線程調用 RequestStop()
方法后,工作線程便立即終止了,運行效果如下圖所示:
這說明加了 volatile
關鍵字后,程序可以實時讀取到字段的最新值。
注意,一定要切換為 Release 模式運行才能看到 volatile
發揮的作用,Debug 模式下即使添加了 volatile
關鍵字,編譯器也是不會執行優化的。
當然,并不是所有的類型都可以使用 volatile
關鍵字修飾的,常見的使用 volatile
的類型是這些簡單類型:sbyte, byte, short, ushort, int, uint, char, float 和 bool,其它的請查看參考鏈接。
上述就是小編為大家分享的c# 實現volatile 關鍵字的拾遺補漏了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。