2012-11-13 27 views
10

這看起來可能有些瘋狂,但如果我可以合理地確定它不會造成奇怪的行爲,那麼這是一種我正在考慮作爲大型圖書館一部分的方法。在線程池中複用C#5.0的異步 - 線程安全嗎?

的方法:

運行異步用戶與SynchronizationContext是分派給一個線程池的代碼。用戶代碼看起來是這樣的:

async void DoSomething() 
{ 
    int someState = 2; 
    await DoSomethingAsync(); 
    someState = 4; 
    await DoSomethingElseAsync(); 
    // someState guaranteed to be 4? 
} 

我不能肯定獲得someState是否是線程安全的。雖然代碼可以在一個「線程」中運行,事實上,這些操作是完全有序的,但它仍然可以在引擎蓋下面的多個線程中分割。如果我的理解是正確的,在x86上的順序應該是安全的,並且由於該變量不被共享,所以我不需要擔心編譯器優化等問題。

更重要的是,我擔心在ECMA或CLR內存模型下這是否會保證線程安全。我很確定我需要在執行排隊工作之前插入內存屏障,但是我對這裏的推理並不完全有信心(或者這種方法可能因爲完全不同的原因而不可行) 。

+5

這是一個局部變量。它怎麼能不是線程安全的? IOW是什麼讓你認爲它可以在另一個線程中被改變? (除非你將某個引用傳遞給某個不顯示的地方,即'ref'或者一個被捕獲的變量)。 – leppie

+3

根據我的理解,'await'將下面的代碼轉換成繼承,當底層的'Task'完成時,它將在當前的'SynchronizationContext'上執行。如果這是調度到線程池,那麼延續可以運行在不同的線程上。它不會以任何方式同時運行*,但我不確定如果延續在另一個物理線程上執行,是否可以保證「someState」的更改可見。 – ShZ

+2

這是一個很好的問題,很多人甚至不知道要問。 –

回答

9

這是回答在async/await FAQ的評論部分:

TPL包括適當的障礙時,任務排隊,並在任務執行的開始/結束,使價值得到適當可見。

所以沒有明確的障礙是必要的。