《Linux 中的執行緒區域性儲存(1)》提到了一種,其實在Linux中還有一種更為高效的執行緒區域性儲存方法,就是使用關鍵字__thread來定義變數。
__thread是GCC內建的執行緒區域性儲存設施(Thread-Local Storage),它的實現非常高效,與pthread_key_t向比較更為快速,其儲存效能可以與全域性變數相媲美,而且使用方式也更為簡單。建立執行緒區域性變數只需簡單的在全域性或者靜態變數的宣告中加入__thread說明即可。列如:
1 2 |
static __thread char t_buf[32] = {'\0'}; extern __thread int t_val = 0; |
凡是帶有__thread的變數,每個執行緒都擁有該變數的一份拷貝,且互不干擾。執行緒區域性儲存中的變數將一直存在,直至執行緒終止,當執行緒終止時會自動釋放這一儲存。__thread並不是所有資料型別都可以使用的,因為其只支援POD(Plain old data structure)[1]型別,不支援class型別——其不能自動呼叫建構函式和解構函式。同時__thread可以用於修飾全域性變數、函式內的靜態變數,但是不能用於修飾函式的區域性變數或者class的普通成員變數。另外,__thread變數的初始化只能用編譯期常量,例如:
1 2 3 |
__thread std::string t_object_1 ("Swift"); // 錯誤,因為不能呼叫物件的建構函式 __thread std::string* t_object_2 = new std::string (); // 錯誤,初始化必須用編譯期常量 __thread std::string* t_object_3 = nullptr; // 正確,但是需要手工初始化並銷燬物件 |
除了以上之外,關於執行緒區域性儲存變數的宣告和使用還需注意一下幾點:
- 如果變數宣告中使用量關鍵字static或者extern,那麼關鍵字__thread必須緊隨其後。
- 與一般的全域性變數或靜態變數一樣,執行緒區域性變數在宣告時可以設定一個初始化值。
- 可以使用C語言取地址符(&)來獲取執行緒區域性變數的地址。
__thread的使用例子可參考 https://github.com/ApusApp/Swift/blob/master/swift/base/logging.cpp 的實現及其單元測試對於那些非POD資料型別,如果想使用執行緒區域性儲存機制,可以使用對pthread_key_t封裝的類來處理,具體方式可參考https://github.com/ApusApp/Swift/blob/master/swift/base/threadlocal.h 的實現以及其的單元測試