C# 在任务中使用ThreadStatic字段

C# 在任务中使用ThreadStatic字段,c#,thread-safety,task-parallel-library,C#,Thread Safety,Task Parallel Library,开始编辑 “正确”的方法是使用SynchronizationContext,如下所述: 我相信在4.5 SynchronizationContext中,使用async/await关键字会自动为您处理,但还并没有做足够的工作来确认 在4.0中,您可能希望利用“TaskScheduler.FromCurrentSynchronizationContext”捕获当前线程的上下文(在我的例子中,这将包括HttpContext,但BCL的各个部分提供类似的构造) 结束编辑 主要问题是: 以下是与任务共享“

开始编辑

“正确”的方法是使用SynchronizationContext,如下所述:

我相信在4.5 SynchronizationContext中,使用async/await关键字会自动为您处理,但还并没有做足够的工作来确认

在4.0中,您可能希望利用“TaskScheduler.FromCurrentSynchronizationContext”捕获当前线程的上下文(在我的例子中,这将包括HttpContext,但BCL的各个部分提供类似的构造)

结束编辑

主要问题是:

以下是与任务共享“上下文”的“安全”机制吗?

在我的用例中,如果不深入太多细节,就不可能直接将上下文下推到操作中

public static class ContextCaller{
    [ThreadStatic]
    public static object SharedState;

    public static Task InvokeWithContext(this Action theAction){
        //We're still running in the "outer" context, 
        //so we can collect a variable and store it in the thread-static
        //field by closing it into the task.
        var context = new object();

        var t = new Task(()=>{
            try{
                //close in the context
                SharedState = context;
                theAction();
            }
            finally{
                //teardown the shared state.
                SharedState = null;
            }
        });
        t.Start();
        return t;
    }
}
现在是客户端代码:

//client code:
Action doWork = ()=>{
    var state = ContextCaller.SharedState;
    //do work on state, potentially throwing an exception in the process.
};

//cause the task to be invoked with some data available only on this thread.
doWork.InvokeWithContext();
根据我对任务和线程之间关系的理解,以上内容应该是安全的,因为:

  • 一个任务将只在一个线程上运行(假设该操作不会产生额外的任务/线程)
  • 设置ThreadStatic字段 在执行“theAction()”之前,和“finally”保证此字段 无论结果如何,在调用“theAction()”后重置

  • 除了显式地将参数关闭到“theAction”之外,还有其他更好的模式用于定义任务的上下文吗?

    我看不出代码不能正常工作的任何技术原因


    但我也认为这样做是一种不好的做法,只有在没有其他方法的情况下,我才会使用这样的方法。我认为在方法中添加另一个重载来执行
    操作
    (或者更好,使用强类型参数)不应该是一个重大的改变。

    我意识到这有点“聪明”,我意识到使用异步/等待支持隐式地在所有地方创建任务,我关于不生成任务的假设将越来越难以实施。我假设不可能将
    操作更改为
    操作,而只将上下文作为参数传递?正确,调用方没有直接访问“上下文”变量的权限,添加它们会给我带来其他问题。我知道我可以通过操作传递状态,问题是“doWork()”对HttpContext有一个间接依赖,它可以/将在任务运行之前消失。如果你在ASP.NET中,为什么要使用
    任务
    s?能否在ASP.NET同步上下文上运行
    任务
    ?我相信这样做可以解决HttpContext依赖性。我将此标记为可接受的答案,因为它确实涵盖了提出的问题,但我认为SynchronizationContext是一条路,并将在上面的问题中概述这一点。