ThreadStatic for TPL Task

如何在TPL任务中使用类似ThreadStatic东西? 我的理解(“使用C#进行Wrox Professional Parallel Programming”,第74页)是一个Task可以在执行期间从一个线程切换到另一个线程。

我想做的事?

我想在静态类中维护一个会话ID,所以我不需要将这个id传递给我的所有方法。 我的库有像login(id)logout(id)方法,以及许多与这个id相关的凭证进行操作的方法。 但我不想将此id传递给每个方法。 我可以确保在不同的线程中为不同的会话调用我的库。 因此,在ThreadStatic变量中保存login()内的id将起作用。

现在我想使用ThreadPool为我创建的TPL任务。 我可以将会话ID传递给Task,但是如果我将这个id存储在ThreadStatic变量中,那么如果我的Task切换线程,它将无法生存。

TPL和.Net 4.5的异步流程是ExecutionContext ,这意味着您可以使用CallContext.LogicalSetData(string, object)CallContext.GetLogicalData(string) ,就像使用ThreadStatic 。 然而,它确实会导致严重的性能损失。

请参阅Async Causality Chain Tracking , 如何在ExecutionContext中包含自己的数据 ,以及ExecutionContext vs SynchronizationContext以进行更深入的潜水。

使用示例:

 class Program { static void Main(string[] args) { Logger.Current = new Logger("Test Printer"); Logger.Current.Print("hello from main"); var t1 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); }); var t2 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); }); Task.WaitAll(t1, t2); } } class Logger { private string LogName; public Logger(string logName) { if (logName == null) throw new InvalidOperationException(); this.LogName = logName; } public void Print(string text) { Console.WriteLine(LogName + ": " + text); } public static Logger Current { get { return CallContext.LogicalGetData("PrinterName") as Logger; } set { CallContext.LogicalSetData("PrinterName", value); } } } 

打印:

测试打印机:你好  
测试打印机:问题来自11号线 
测试打印机:你好,来自主题10

我会说避免线程静态,除非你能确定哪些任务在哪些线程上运行。 只是通过它。 你的意图会更清楚。

你是对的,线程静态不适合任务。

通过传递参数更好地克服您的问题。 通过它会更清晰,更清洁。 一点点打字会让你获得更多的可读性和线程安全性。