2017-01-30 68 views
4

我正在看看在http://www.albahari.com/threading/part4.aspx 中描述的內存障礙部分,並試圖做一個異步/ await版本的例子'我們真的需要鎖和障礙?': 線程安全異步/等待與內存緩存

public class Program 
{ 
    static void Main(string[] args) 
    { 
     TestAsync(); 
     Console.ReadKey(true); 
    } 

    private static async void TestAsync() 
    { 
     bool complete = false; 
     Func<Task> testFunc = async() => 
     { 
      await Task.Delay(1000); 
      bool toggle = false; 
      while (!complete) toggle = !toggle; 
     }; 

     var task = testFunc(); 
     Thread.Sleep(2000); 
     complete = true; 
     await task; 
     Console.WriteLine("Done"); 
    } 
} 

當沒有調試下發行模式中運行,程序將永遠不會完成按照原來的線程例如,它是基於關閉。

但是,由於上下文被保存的方式,我受到了異步/等待的印象,它會阻止這些類型的問題。或者在使用異步/等待時所有線程安全規則仍然適用?

回答

6

這實際上是一個編譯優化問題。當您因爲某種原因而在發行版中進行編譯時,它預測完成永遠不會是真的,並且無限地運行您的應用程序既然你已經基於另一個例子,我猜你已經知道了。但只要異步/等待它不能被指責。

爲了使這項工作,你仍然需要一套完整的爲volatile變量,像這樣:

 static volatile bool complete = false; 

這將告訴編譯器檢查它的每一個週期而不管,它會工作。

我不是說我同意它,但是發生了什麼事情是編譯器看到完整的變化一直到while(!complete)部分的點,並且由於沒有volatile關鍵字,它決定它永遠不會去改變以優化性能。

使這項工作的另一種方法是刪除編譯器優化。您可以單擊項目屬性,然後單擊生成選項卡,並取消選中「優化代碼」。然後它將在發佈中工作。

+0

雖然這將確實解決問題,[Eric Lippert本人不鼓勵使用易失性](https://blogs.msdn.microsoft.com/ericlippert/2011/06/16/atomicity-volatility-and-immutability-是不同的 - 第三/) – Rob

+1

好吧,像Eric Lippert在總結中所熟悉的那樣,他肯定比任何事情都更加咆哮,並用它來強制一個肯定是錯誤的觀點。在C#中,布爾(布爾)字段是原子的,這意味着它總是線程安全的。絕對沒有理由對布爾進行鎖定,因爲這會導致性能下降。不要相信我,請嘗試測試它,因爲我有。看到布爾是原子的,並且總是線程安全的,我們可以將它用於多線程的事情。然而;以防止編譯器優化我們添加的volatile變量。我只是不同意Eric。 –

+0

謝謝,我想盡可能多,認爲可能有更多的保存上下文時使用異步/等待 – aprofessionalpirate