2014-05-09 66 views
3

正在使用ThreadStatic並在每次等待完成「一個選項」時設置上下文?有另一種方法嗎?如何在C#中通過異步等待模型維護線程上下文?

public async void Test() 
{ 
    // This is in Thread 1 
    Foo foo = new Foo(); 
    Context.context = "context1"; // This is ThreadStatic 
    string result = await foo.CallAsynx(); 

    // This is most likely Thread 2 
    Context.context = "context1"; // This might be a different thread and so resetting context  
} 

現在有另一種方法,如果我不想使用ThreadStatic?

+1

你真的需要線程'ThreadStatic'嗎?你可以通過'CallContext.LogicalSetData' /'LogicalGetData'來流動你的全局狀態變量:http://stackoverflow.com/q/22363830/1768303 – Noseratio

+1

或者你可以把它改成'foo.CallAsynx(context);'。這就是ASP.NET MVC的方式。 –

+1

此外,異步不會創建新線程。我會和Paulo一起解決問題。在ASP.NET上下文中,(線程)靜態是不安全的,不同的請求在線程池中運行在線程上,所以(線程)靜態變量將存活,並在需求/用戶之間共享。 – MarkO

回答

13

ThreadStaticThreadLocal<T>,數據線插槽和CallContext.GetData/CallContext.SetDataasync很好地工作,因爲他們是線程特定的。

的最佳替代方案是:

  1. 將它作爲一個參數作爲@PauloMorgado建議。等同地,您可以將其設置爲對象的字段成員(它通過this隱式地作爲參數傳遞);或者你可以讓你的lambdas捕獲變量(在下面,編譯器會通過this隱式地將它作爲參數傳遞)。
  2. 使用HttpContext.Items(如果您位於ASP.NET 4.5)。
  3. 按照@Noseratio的建議使用CallContext.LogicalGetData/CallContext.LogicalSetData。您只能在邏輯線程上下文中存儲不可變數據;它只能在.NET 4.5上運行,並不適用於所有平臺(例如Win8)。
  4. 通過爲該線程安裝一個「主循環」(例如AsyncContext from my AsyncEx library),強制所有async延續回到同一線程。
+0

我正在試驗CallContext.LogicalGetData和CallContext.LogicalSetData,看起來像這樣可以用於我們的場景。此外,斯蒂芬 - 我遇到了「隱式異步上下文」的博客。偉大的博客。你知道LogicalGetData/LogicalSetData是如何在內部設計的?我希望它不使用ThreadStatic :) – Ashwin

+2

不,它不使用'ThreadStatic'。 :)「邏輯調用上下文」是[執行上下文的一部分](http://blogs.msdn.com/b/pfxteam/archive/2012/06/15/executioncontext-vs-synchronizationcontext.aspx),即(淺),由您的代碼「流動」到其他線程時由框架複製。在.NET 4.5中,邏輯調用上下文獲得了寫時複製行爲,這使得它能夠按照異步代碼的預期工作。 –

+0

Stephen,回覆:「它僅適用於.NET 4.5,並不適用於所有平臺(例如Win8)。」你的意思是WinPho 8? – Mike