32

Consider the following example (lock guards on cout omitted for simplicity).

#include <future> #include <iostream> #include <thread> using namespace std; struct C { C() { cout << "C constructor\n";} ~C() { cout << "C destructor\n";} }; thread_local C foo; int main() { int select; cin >> select; future<void> f[10]; for ( int i = 0;i < 10; ++i) f[i] = async( launch::async,[&](){ if (select) foo; } ); return 0; } 

On both clang and gcc, this program outputs nothing if the user writes '0', while it prints Constructor/Destructor 10 times if the user inputs a non zero number. Additionally clang complains about an obvious non used expression result.

Since a thread_local storage life-time is supposed to span the entire thread's life, I expected the foo variable to be initialized in every thread regardless of the user input.

I might want to have a thread-local variable for the sole purpose of having a side-effect in the constructor, does the standard mandates that a thread_local object is initialized on its first use?

1 Answer 1

27

The standard allows for this behavior, although it doesn't guarantee it. From 3.7.2/2 [basic.stc.thread]:

A variable with thread storage duration shall be initialized before its first odr-use (3.2) and, if constructed, shall be destroyed on thread exit.

It's also possible that the objects are constructed at some other time (e.g. on program startup), as "before first use" means "at any point as long as it is before" rather than does "just before".

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you, my CTRL+F skills are quite limited :)
This is somewhat misleading; the standard says that a variable with thread-local storage duration must be initialized sometime before it is odr-used, but it doesn't mandate exactly when it will be initialized, and an implementation is even permitted to initialize such variable even if the variable is never odr-used. As stated: it can be initialized at the latest when the variable is odr-used, but such initialization can happen at any time before that.
@FilipRoséen-refp: I didn't quite realize yesterday that the answer read like that if taken literally, but you are right on both counts. I have edited to make it clear that "before first use" is meant in the mathematical sense. Thank you for the feedback.
@shuva nothing would change.
Hmmm... It would seem that the definition of the global "thread_local C foo;" constitutes ODR-use. This is opposed to, say, a thread_local static that is local to a function which would only be ODR-use'd if that function were entered. I have found that MSVC creates these thread_local globals without them being used, whereas clang/gcc only creates them if they are used.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.