2014-05-09 67 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