Are C++11 thread_local variables automatically static?
Asked Answered
L

4

112

Is there a difference between these two code segments:

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

and

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

Backstory: originally I had a STATIC vector V (for holding some intermediate values, it gets cleared every time I enter the function) and a single-threaded program. I want to turn the program into a multithreading one, so somehow I have to get rid of this static modifier. My idea is to turn every static into thread_local and not worry about anything else? Can this approach backfire?

Leftward answered 1/4, 2014 at 18:49 Comment(5)
Having a thread_local local variable makes no sense to begin with … each thread has its own call stack.Weaponry
Several C functions were originally written to return the address of static or global variables. This was later found to lead to obscure bugs when used in multi-threaded apps (e.g. errno, localtime). In addition, at times it is very detrimental to protect shared variables with a mutex when a function is being called from multiple threads or to have to pass a thread context object among many call objects and methods.. Variables that are local to a thread solve these and other issues.Surgeonfish
@Konrad Rudolph declaring local variables solely as static rather than static thread_local does not initialize one instance of the variable for each thread.Chishima
@Chishima That’s not the point, either of me or of the OP. We’re not talking about static vs static thread_local but rather about auto vs thread_local, using the pre-C++11 meaning of auto (i.e. automatic storage).Weaponry
Also see How to define thread-local local static variables?. A quick language lawyer note... Microsoft and TLS support changed around Vista; see Thread Local Storage (TLS). The change affects things like Singleton's and may or may not apply. If you are using the abondware software model then you will probably be OK. If you are happy to support multiple compilers and platforms then you may have to pay attention to it.Nickels
P
131

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.

Poinciana answered 1/4, 2014 at 19:2 Comment(5)
static and extern thus do not imply storage class but only linkage for thread_local variables even in inner scopes.Soulsearching
@Soulsearching Block scope variables have no linkage. So your resume is wrong. As I wrote in the post they have thread storage duration. It is in fact the same as static storage duration but applied to each thread.Poinciana
If you add the extern, you are doing a declaration not a definition. So?Soulsearching
@Soulsearching So it means that definitions of block scope variables have no linkage.Poinciana
I just tried that in VS 2013 and it shouts "TL variables cannot be dynamically initialized". I'm puzzled.Brookins
A
22

Yes, "thread-local storage" is very similar to "global" (or "static storage"), only that instead of "duration of the entire program" you have "duration of the entire thread". So a block-local thread-local variable is initialized the first time control passes through its declaration, but separately within each thread, and it's destroyed when the thread ends.

Alimentary answered 1/4, 2014 at 19:0 Comment(2)
I don't understand, automatic variables also does the same thing ? Then what is the need of thread_local ?Ileneileo
@RupeshYadav. The thread local variable is initialized only once per thread, automatic variable once per function call.Bramlett
C
8

When used with thread_local, static is implied in block-scope (see @Vlad's answer), requied for a class member; I guess, means linkage for namespace scope.

Per 9.2/6:

Within a class definition, a member shall not be declared with the thread_local storage-class-specifier unless also declared static

To answer the original question:

Are C++11 thread_local variables automatically static?

There is no choice, except for namespace-scope variables.

Is there a difference between these two code segments:

No.

Claudeclaudel answered 14/10, 2015 at 16:22 Comment(0)
C
7

Thread local storage is static but it behaves quite differently from simple static storage.

When you declare a variable static there is exactly one instance of the variable. The compiler/runtime system guarantees that it will be initialized for you sometime before you actually use it, without specifying exactly when (some details omitted here.)

C++11 guarantees that this initialization will be thread safe, however before C++11 this thread safety was not guaranteed. For example

static X * pointer = new X;

could leak instances of X if more than one thread hit the static initialization code at the same time.

When you declare a variable thread local there are potentially many instances of the variable. You could think of them as being in a map that was indexed by thread-id. That means each thread sees its own copy of the variable.

Once again, if the variable is initialized the compiler/runtime system guarantees that this initialization will happen before the data is used and that the initialization will happen for each thread that uses the variable. The compiler also guarantees that initiation will be thread safe.

The thread safety guarantees means that there can be quite a bit of behind-the-scenes code to make the variable behave the way you expect it to -- especially considering that the compiler has no way of knowing ahead of time exactly how many threads will exist in your program and how many of these will touch the thread local variable.

Chops answered 1/4, 2014 at 19:19 Comment(3)
@Etherealone: Interesting. Which particular information? Can you provide a reference?Chops
https://mcmap.net/q/17220/-is-local-static-variable-initialization-thread-safe-in-c-11-duplicate . Wikipedia C++11 article mentions it if I remember right.Idocrase
However, static objects are first initialized, then copy assigned. So I am also a little unclear whether thread-safe initialization includes the full expression. It probably does though because otherwise it wouldn't be considered thread-safe.Idocrase

© 2022 - 2024 — McMap. All rights reserved.