What Does the Thread_Local Mean in C++11

What does the thread_local mean in C++11?

Thread-local storage duration is a term used to refer to data that is seemingly global or static storage duration (from the viewpoint of the functions using it) but in actual fact, there is one copy per thread.

It adds to the current automatic (exists during a block/function), static (exists for the program duration) and dynamic (exists on the heap between allocation and deallocation).

Something that is thread-local is brought into existence at thread creation and disposed of when the thread stops.

Some examples follow.

Think of a random number generator where the seed must be maintained on a per-thread basis. Using a thread-local seed means that each thread gets its own random number sequence, independent of other threads.

If your seed was a local variable within the random function, it would be initialised every time you called it, giving you the same number each time. If it was a global, threads would interfere with each other's sequences.

Another example is something like strtok where the tokenisation state is stored on a thread-specific basis. That way, a single thread can be sure that other threads won't screw up its tokenisation efforts, while still being able to maintain state over multiple calls to strtok - this basically renders strtok_r (the thread-safe version) redundant.

Both these examples allow for the thread local variable to exist within the function that uses it. In pre-threaded code, it would simply be a static storage duration variable within the function. For threads, that's modified to thread local storage duration.

Yet another example would be something like errno. You don't want separate threads modifying errno after one of your calls fails but before you can check the variable, and yet you only want one copy per thread.

This site has a reasonable description of the different storage duration specifiers.

Why does C++11 allow you to declare a local variable as thread_local?

According to the standard, a thread_local variable at block scope is also implicitly static. However, not all static variables are thread_local.

So

 int main()
{
thread_local int x;
}

is actually equivalent to

 int main()
{
thread_local static int x;
}

but different from;

 int main()
{
int x; // auto implied
}

Are C++11 thread_local variables automatically static?

According to the C++ Standard

When thread_local is applied to a variable of block scope the
storage-class-specifier static is implied if it does not appear
explicitly

So it means that this definition

void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

is equivalent to

void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

However, a static variable is not the same as a thread_local variable.

1 All variables declared with the thread_local keyword have thread
storage duration. The storage for these entities shall last for the
duration of the thread in which they are created. There is a distinct
object or reference per thread, and use of the declared name refers to
the entity associated with the current thread

To distinguish these variables the standard introduces a new term thread storage duration along with static storage duration.

thread_local vs local variable in C++

thread_local implies static when static is omitted.

A local static variable preserves its value when a given function is called multiple times. You may read about static variable elsewhere.

Now, I assume you do know what static variable is - the important things are just:

  • static variables have local scope
  • (but) static variables have global existence

The second point makes a static variable's memory accessible to other functions by C++ references and pointers - it proves that the static variable has just one copy - across all threads of the process. You need to know what threads are and how to create/program threads.

Now, to the question. You know that Global variables have global scope and global accessibility, but when you run two or more instances of your program, both/all of them would have a SEPARATE copy of that global variable. That means each process would have a separate copy of that global variable.

So, what if you wanted to have a SEPARATE copy of static variable per thread? You use thread_static. Each thread will have a separate copy of that static variable.

Interestingly, you can apply thread_local to global variables also - thence each thread will receive a separate copy of those global variables also!

// Globals
int counter;
thread_local int this_thread_counter; // Each thread will have separate copy

Now, think how strtok would work - think about the (concurrent) calls to strtok !

QThreadStorage vs C++11 thread_local

Well, since Qt is open-source you can basically figure out the answers from the Qt sources. I am currently looking at 5.9 and here are some things, that I'd classify as significant:

1) Looking at qthreadstorage.cpp, the get/set methods both have this block in the beginning:

QThreadData *data = QThreadData::current();
if (!data) {
qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
return 0;
}

So (an maybe this has changed/will change) you can't mix QThreadStorage with anything else than QThread, while the thread_local keyword does not have similar restrictions.

2) Quoting cppreference on thread_local:

thread storage duration. The object is allocated when the thread begins and deallocated when the thread ends.

Looking at qthreadstorage.cpp, the QThreadStorage class actually does not contain any storage for T, the actual storage is allocated upon the first get call:

QVector<void *> &tls = data->tls;
if (tls.size() <= id)
tls.resize(id + 1);
void **v = &tls[id];

So this means that the lifetime is quite different between these two - with QThreadStorage you actually have more control, since you create the object and set it with the setter, or default initialize with the getter. E.g. if the ctor for the type could throw, with QThreadStorage you could catch that, with thread_local I am not even sure.

I assume these two are significant enough not to go any deeper.

C++ - Where are thread_local variables stored?

1. As I understand, both threads will get their own copy of this variable, correct?

Yes. Each thread gets its own copy of the thread_local variable.

2. Where exactly is the thread local variable stored in memory? If data segment, how exactly does the right variable gets picked up during execution?

thread_local is the implementation of the Thread Local Storage concept. TLS is implemented as a table of slots withing each thread object. Each thread having its own copy of the table. For e.g in Windows implementation of TLS this table is within the Thread Information Block of a thread. When a global/static variable is declared as thread_local, it would get associated with a table slot of each thread at the same offset. When the thread_local variable is accessed by a thread then using the current thread context, the thread's own copy of the variable associated with the table slot within this thread object is accessed. Please check this link for more detail on TLS implementation. https://en.wikipedia.org/wiki/Thread-local_storage

C++: How to use thread_local to declare a pointer variable?

The thread_local static std::unique_ptr<A> s_a; works. The memory in task manager is not true. I used vld to demonstrate the memory, No memory leaks detected.



Related Topics



Leave a reply



Submit