ThreadStatic for TPL Task

时间:2011-08-01 09:45:05

标签: c# .net multithreading

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

我想做什么?

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

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

3 个答案:

答案 0 :(得分:4)

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

请参阅Async Causality Chain TrackingHow to include own data in ExecutionContextExecutionContext 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);
        }
    }
}

打印:

Test Printer: hello from main  
Test Printer: hello from thread 11 
Test Printer: hello from thread 10

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

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