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延遲綁定,不需要我們初始化,帶來的代價就是第一條。
- 兩個關鍵字都支持類的構造與析構。
作者水平有限,有問題的地方還請大家給出寶貴的建議。
參考: