96

这两个代码段之间是否有区别:

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

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

背景故事:最初我有一个静态向量 V(用于保存一些中间值,每次进入函数时都会被清除)和一个单线程程序。我想把程序变成一个多线程的程序,所以我必须以某种方式摆脱这个静态修饰符。我的想法是把每一个静态都变成thread_local,而不用担心别的?这种方法会适得其反吗?

4

4 回答 4

109

根据 C++ 标准

当 thread_local 应用于块范围的变量时,如果它没有显式出现,则隐含存储类说明符 static

所以这意味着这个定义

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

相当于

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

但是,静态变量thread_local 变量不同。

1 所有使用 thread_local 关键字声明的变量都有线程存储持续时间。这些实体的存储将持续到创建它们的线程的持续时间。每个线程有一个不同的对象或引用,使用声明的名称是指与当前线程关联的实体

为了区分这些变量,标准引入了一个新术语线程存储持续时间以及静态存储持续时间。

于 2014-04-01T19:02:03.700 回答
21

是的,“线程本地存储”与“全局”(或“静态存储”)非常相似,只是你有“整个线程的持续时间”而不是“整个程序的持续时间”。因此,块局部线程局部变量在控制第一次通过其声明时被初始化,但在每个线程中是分开的,并且在线程结束时被销毁。

于 2014-04-01T19:00:32.423 回答
6

与 ,一起使用时thread_localstatic隐含在块范围中(请参阅@Vlad 的答案),需要类成员;我想,意味着命名空间范围的链接。

根据 9.2/6:

在类定义中,不得使用 thread_local 存储类说明符声明成员,除非也声明为静态

要回答原始问题:

C ++ 11 thread_local变量是否自动静态?

除了命名空间范围的变量外,别无选择。

这两个代码段之间是否有区别:

不。

于 2015-10-14T16:22:41.087 回答
5

线程本地存储是静态的,但它的行为与简单的静态存储完全不同。

当您声明一个静态变量时,该变量只有一个实例。编译器/运行时系统保证它将在您实际使用它之前的某个时间为您初始化,而不指定确切的时间(这里省略了一些细节。)

C++11 保证这个初始化是线程安全的,但是在 C++11 之前这个线程安全并不能保证。例如

static X * pointer = new X;

如果多个线程同时访问静态初始化代码,则可能会泄漏 X 的实例。

当您声明变量线程本地时,可能有许多变量实例。您可以将它们视为在由 thread-id 索引的地图中。这意味着每个线程都可以看到自己的变量副本。

再一次,如果变量被初始化,编译器/运行时系统保证这个初始化将在数据被使用之前发生,并且初始化将发生在每个使用该变量的线程上。编译器还保证启动是线程安全的。

线程安全保证意味着可以有相当多的幕后代码来使变量按照您期望的方式运行——特别是考虑到编译器无法提前知道究竟有多少线程将存在于您的程序中,其中有多少会触及线程局部变量。

于 2014-04-01T19:19:00.037 回答