【问题标题】:When is a `thread_local` global variable initialized?什么时候初始化 `thread_local` 全局变量?
【发布时间】:2014-08-06 20:41:26
【问题描述】:

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

【问题讨论】:

    标签: c++ multithreading c++11 thread-local


    【解决方案1】:

    标准允许这种行为,尽管它不能保证。从 3.7.2/2 [basic.stc.thread]:

    具有线程存储持续时间的变量应在之前初始化 其首次 odr 用途 (3.2),如果建造,则应在 线程退出。

    也有可能在其他时间(例如在程序启动时)构造对象,因为“首次使用之前”的意思是“只要它在之前”,而不是“就在之前”。

    【讨论】:

    • 谢谢你,我的CTRL+F 技能非常有限:)
    • 这有点误导;该标准规定,具有线程本地存储持续时间的变量必须在使用 odr 之前的某个时间进行初始化,但它并没有明确规定 何时 它将被初始化,甚至允许实现即使从未使用过该变量,也要初始化此类变量。如前所述:当变量被 odr-used 时,它可以在 latest 初始化,但这种初始化可以在此之前的任何时间发生。
    • @FilipRoséen-refp:昨天我并没有完全意识到,如果从字面上看,答案是这样的,但你在这两个方面都是对的。我已经编辑清楚地表明“首次使用之前”是指数学意义上的。感谢您的反馈。
    • @shuva 什么都不会改变。
    • Hmmm... 似乎全局“thread_local C foo;”的定义构成 ODR 使用。这与某个函数本地的 thread_local 静态变量相反,该函数只有在输入该函数时才会被 ODR 使用。我发现 MSVC 在不使用它们的情况下创建这些 thread_local 全局变量,而 clang/gcc 只有在使用它们时才创建它们。
    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 2017-04-10
    相关资源
    最近更新 更多