此問題探討了 C# 執行緒行為中的潛在異常,與競爭條件或鎖定需求無關。具體來說,問題在於執行緒是否可以快取某個值並忽略其他執行緒上對該值所做的更改,從而可能導致意外行為。
管理記憶體的 NET 執行階段被認為可以緩解此問題。然而,一些文獻另有說法,斷言某些程式碼結構(如下所示)可能會導致無限循環:
class BackgroundTaskDemo { private bool stopping = false; static void Main() { BackgroundTaskDemo demo = new BackgroundTaskDemo(); new Thread(demo.DoWork).Start(); Thread.Sleep(5000); demo.stopping = true; } static void DoWork() { while (!stopping) { // Do something here } } }
根據引用的文章(http://www.yoda.arachsys.com/ csharp/threads/volatility.shtml , http://softwareengineering.stackexchange.com/questions/104757/is-a-string-property-itself-threadsafe),讀取執行緒可能會快取停止變數的初始值,使所有後續更新不可見並導致執行緒無限期地運行。
但是,記憶體建模專家堅持 C# 規格不保證這種行為。雖然提供的程式碼通常可以正確運行,但它依賴於特定於平台和編譯器的最佳化,而不是特定的語言語義。
為了進一步說明該問題,請考慮以下修改後的程式碼:
using System.Threading; using System; static class BackgroundTaskDemo { //make this volatile to fix it private static bool stopping = false; static void Main() { new Thread(DoWork).Start(); Thread.Sleep(5000); stopping = true; Console.WriteLine("Main exit"); Console.ReadLine(); } static void DoWork() { int i = 0; while (!stopping) { i++; } Console.WriteLine("DoWork exit " + i); } }
透過此修改,程式碼可以預見地輸出“Main exit”,但DoWork 方法會無限期地繼續運行。這個反例表明,儘管最初有懷疑,C# 運行時並不總是保證跨線程值更新的一致性。
為了解決這種歧義,可以將 volatile 關鍵字應用於停止變數。易失性修飾符強制對變數進行原子訪問,防止快取的值掩蓋實際更新。
以上是C# 執行緒可以忽略其他執行緒的值變更嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!