執行緒上快取的值可以忽略其他執行緒上所做的變更嗎?
這個問題重點討論 C# 執行緒是否可以快取值並忽略隨後在不同執行緒上對該值進行了更改。儘管關於競爭條件、原子性和鎖的使用等常識,該查詢特別針對 .NET 運行時可能抽像出易失性記憶體問題的場景。
一些消息來源聲稱,在以下程式碼中,讀取線程可能會「停止」快取bool 變數的初始值,並且永遠不會檢測到其修改,這可能會導致無限循環:
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 } } }
但是,此聲明的有效性是有爭議。批評者質疑 .NET 運行時是否真的會像所聲稱的那樣忽略記憶體值的變更。他們指出給定的代碼「幾乎肯定」有效,這意味著該聲明是沒有根據的。
問題的關鍵在於聲明中所描述的行為不受 .NET 規範的保證。雖然它在大多數情況下可能有效,但不能保證在所有情況下都有效。記憶體模型領域的專家警告不要依賴這種不可靠的結果。
此外,還提出了一個可驗證的反例,演示了程式碼按預期失敗的特定場景。在以下修改後的程式碼中,「stopping」被聲明為volatile 以修正該問題:
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); } }
當在沒有volatile 關鍵字的「release」模式下運行時,程式碼會進入無限循環並無限期地繼續運行,即使「停止」已設為true 後。但是,在“停止”變數中添加“易失性”可以解決該問題,使循環按預期退出。
結論是,雖然程式碼通常看起來可以正常運行,但不能保證能夠正常運行一致。對於健全且可靠的多執行緒程式碼,強烈建議使用鎖定或 volatile 關鍵字。
以上是C# 執行緒可以快取布林值並忽略其他執行緒上的後續變更嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!