gcc版本为(gcc version 7.3.0 (Debian 7.3.0-19))
引言
两个关键字都是关于线程存储的,不过一个是C语言的,一个是C++11的特性。它们之间有什么区别呢?因为在CSDN没有找到解答,遂在解答中对过程进行记录,以帮助有同样疑惑的同学。
过程
__thread is supported on GNU, clang and more. It was available before thread_local… they are not equivalent and both are supported. the difference is that thread_local uses lazy initialization to initialize the variable in only threads that access it. __thread does not initialize at all and you must manually initialize it per thread. thread_local thus has an overhead per access and __thread does not. Apple’s compilers disable thread_local and not thread because of this inefficiency, Although __thread is not available on all compilers, __thread is available with GNU tools
__thread被GNU支持,clang等支持.它在thread_local之前是很有用的…它们之间并不相等,而且一般都被支持.它们之间的不同就是thread_local在访问变量的线程中使用延迟初始化来初始话变量.而__thread并不初始化,您必须手动初始化.所以每一次thread_local都是有开销的,而__thread没有.因为这种低效率,Apple的编译器禁用thread_local而不禁用thread,尽管__thread不是在所有编译器上都可用,但_其在GNU工具中可用.(thread_local是C++11的特性)
我们可以看到区别就是延迟初始化带来的效率上的区别,这里的的开销指的是什么呢?开销就是 thread_local 变量的每次使用都将成为一个函数调用。这让人感到不可思议。
这里的过程可以查看参考[4],因为C++生成的汇编代码实在是过于复杂,我在我机子上生成汇编以后看了半天没看出来,所以大家直接查看参考即可,那篇文章还是比较详细的。
看到有些地方说__thread不支持class相关的构造,析构,我们写一个代码看看:
#include <bits/stdc++.h>
using namespace std;
class local_{
public:
local_(){
cout << "hello world\n";
}
void show(){
cout << "hello world1\n";
}
~local_(){
cout << "hollo world2\n";
}
};
thread_local local_ Temp;
//__thread local_ TT;
void test(){
thread_local local_ T;
//static __thread local_ T;
Temp.show();
}
int main(){
auto T = std::thread(&test);
T.join();
cout << "T\n";
return 0;
}
输出:
hello world
hello world
hello world1
hollo world2
hollo world2
没有什么问题,线程局部变量和全局的Temp都经历了一次构造和析构。
那么如果使用__thread的话呢?我们注释掉thread_local local_ Temp
这一句,使用__thread,得到这样的结果:
non-local variable ‘TT’ declared ‘__thread’ needs dynamic initialization
需要动态初始化,__thread是不支持非函数本地变量的。那么如果让它跑起来呢,我们执行动态初始化就可以了,我们需要把代码修改成如下:
static __thread local_* Temp = nullptr;
void test(){
//thread_local local_ T;
//static __thread local_ T;
Temp = new local_();
Temp->show();
delete Temp;
}
输出为:
hello world
hello world1
hollo world2
这样就可以了,没有什么问题。
如果我们把线程局部的thread_local换成__thread呢,我们来看看会发生什么:
hello world
hello world
hello world1
hollo world2
hollo world2
没有什么问题。仍然会发生构造和析构,所以传言被打破了。
结论
通过以上测试与查阅资料,得出以下结论。
- 执行阶段的效率问题。__thread不会发生函数调用,而thread_local对变量的一次访问就是一次函数调用。
- __thread在某些平台上支持,比如GNU,clang等,但是有些平台不支持。thread_local作为C++11的特性,基本都被支持。
- __thread在实现非函数本地变量的时候需要手动初始化,而thread_local延迟绑定,不需要我们初始化,带来的代价就是第一条。
- 两个关键字都支持类的构造与析构。
作者水平有限,有问题的地方还请大家给出宝贵的建议。
参考: