Search code examples
.netasynchronousthreadpooltask-parallel-librarythread-local-storage

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


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


Solution

  • 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;
        });