Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 405
Erick T Avatar asked Nov 01 '11 00:11

Erick T


People also ask

How does TLS relate to the storage of data used by a thread?

Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process can allocate locations in which to store thread-specific data. Dynamically bound (run-time) thread-specific data is supported by way of the TLS API (TlsAlloc).

How is thread local storage implemented?

Thread-local storage (TLS) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread. The run-time model GCC uses to implement this originates in the IA-64 processor-specific ABI, but has since been migrated to other processors as well.

What is the purpose of thread local storage?

Thread Local Storage (TLS) is the mechanism by which each thread in a given multithreaded process allocates storage for thread-specific data. In standard multithreaded programs, data is shared among all threads of a given process, whereas thread local storage is the mechanism for allocating per-thread data.

What is thread local storage C++?

Introduction to C++ thread_local. In C++, thread_local is defined as a specifier to define the thread-local data and this data is created when the thread is created and destroyed when the thread is also destroyed, hence this thread-local data is known as thread-local storage.


1 Answers

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;
    });
like image 101
Reed Copsey Avatar answered Nov 16 '22 17:11

Reed Copsey