`thread_local`全局变量何时初始化?

30
考虑以下示例(为简单起见,对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对象在第一次使用时被初始化?

1个回答

25
标准允许这种行为,尽管它不能保证。根据3.7.2/2 [basic.stc.thread]规定:
一个具有线程存储期的变量必须在其第一次odr使用(3.2)之前进行初始化,并且如果已构造,它必须在线程退出时被销毁。
也可能会在其他时间构造这些对象(例如,在程序启动时),因为“在第一次使用之前”意味着“只要在之前的任何时候”,而不是“就在紧接着之前”。

谢谢,我的CTRL+F技能非常有限 :) - sbabbi
15
有些误导,标准规定线程本地存储期变量必须在 odg 使用之前的某个时间点进行初始化,但并没有强制规定确切的初始化时间。即使这种变量从未被 odg 使用,实现也可以对其进行初始化。因此,它最迟可以在 odg 使用变量时初始化,但实际上可以在此之前的任何时间进行初始化。 - Filip Roséen - refp
@FilipRoséen-refp:昨天我并没有完全意识到如果字面理解,答案会读起来像那样,但你在两个方面都是正确的。我已经进行了编辑,以明确“首次使用之前”是指数学意义上的。感谢您的反馈。 - Jon
1
@shuva 什么都不会改变。 - Jon
@DavidBien,“静态局部变量”一节特指在块作用域声明的变量。(请注意,如果thread_local是应用于块作用域变量的唯一存储类说明符,则隐含使用static,所以你是正确的)。然而,问题中的foo是在全局(全局命名空间)作用域中声明的,并且没有隐含的静态属性。 - kwsp
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接