How to manage Thread Local Storage (TLS) when using TPL?

此生再无相见时 提交于 2019-12-04 18:19:53

问题


I want to store logging context information in TLS so that I can set a value at the entry point, and have that value available in all resulting stacks. This work well, but I also using TPL and the ThreadPool. The problem then becomes how to migrate TLS data to the other threads. I can do it all myself, but then I lose nice methods like Parallel.For.

Is there some way to have TLS copied when using TPL? This will also apply to C# when it gets the await feature.

Thanks, Erick


回答1:


Typically, this is handled via using an overload of Parallel.For that already provides for thread local data.

This overload allows you to provide an initialization and a finalization delegate, which effectively becomes an initialization per thread for your thread local data, and a reduction function at the end to "merge" the results together (which is run once per thread). I wrote about this in detail here.

The basic form is to do something like:

object sync = new object();
double result = 0;

Parallel.For(0, collection.Count, 
    // Initialize thread local data:
    () => new MyThreadSpecificData(),
    // Process each item
    (i, pls, currentThreadLocalData) => 
    {
        // Generate a NEW version of your local state data
        MyThreadSpecificData newResults = ProcessItem(collection, i, currentThreadLocalData);
        return newResults;
    },
    // Aggregate results
    threadLocalData =>
    {
       // This requires synchronization, as it happens once per thread, 
       // but potentially simultaneously
       lock(sync)
          result += threadLocalData.Results;
    });



回答2:


I found another solution to the problem that doesn't require code. I was able to use CallContext to attach data to a "logical thread". This data is transferred from the starting thread to threads generated by TPL as well as the ThreadPool.

http://www.wintellect.com/CS/blogs/jeffreyr/archive/2010/09/27/logical-call-context-flowing-data-across-threads-appdomains-and-processes.aspx




回答3:


There is, of course, yet another alternative: Write a TaskLocal(T) class, like we did, that bases the storage on the current Task, rather than the current Thread. Honestly, I have no idea why Microsoft didn't do this as part of their initial Task implementation.

Important Implementation note: Because Task code that calls await can be split, and resume as a different TaskId, you also need to do what we also did, and implement a method in TaskLocal(T) that maps new TaskIds to previous ones, then save the original TaskId at the start of the Task, and map it after every await call.



来源:https://stackoverflow.com/questions/7961233/how-to-manage-thread-local-storage-tls-when-using-tpl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!