Рассмотрим следующий пример (блокировка охранников на cout
опущено для простоты).
#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;
}
И на clang, и на gcc эта программа ничего не выводит, если пользователь пишет «0», пока печатает Constructor
/Destructor
10 раз, если пользователь вводит ненулевое число.
Кроме того, Clang жалуется на очевидный неиспользованный результат выражения.
Так как thread_local
срок хранения должен охватывать весь поток, я ожидал foo
переменная, которая будет инициализирована в каждом потоке, независимо от пользовательского ввода.
Я мог бы хотеть иметь thread-local
переменная с единственной целью иметь побочный эффект в конструкторе, делает ли стандартный мандат, что thread_local
объект инициализируется при первом его использовании?
Стандарт допускает такое поведение, хотя и не гарантирует его. От 3.7.2 / 2 [basic.stc.thread]:
Переменная с продолжительностью хранения потока должна быть инициализирована до
его первое использование odr (3.2) и, если оно будет построено, должно быть уничтожено
выход из нити.
Также возможно, что объекты создаются в какое-то другое время (например, при запуске программы), поскольку «перед первым использованием» означает «в любой момент до тех пор, пока это происходит до», а не «непосредственно перед».