線程局部存儲(chǔ)
線程局部存儲(chǔ)(TLS,thread local storage) 就是擁有線程生命周期及線程可見(jiàn)性的變量。
線程局部存儲(chǔ)實(shí)際上是由單線程程序中的全局/靜態(tài)變量被應(yīng)用到多線程程序中被線程共享而來(lái)。我們可以簡(jiǎn)單地回顧一下所謂的線程模型。通常情況下,線程會(huì)擁有自己的棧空間,但是堆空間、靜態(tài)數(shù)據(jù)區(qū)則是共享的。這樣一來(lái),全局、靜態(tài)變量在這種多線程模型下總是再線程間共享的。
全局,靜態(tài)變量的共享會(huì)帶來(lái)好處,但是并不是所有的全局,靜態(tài)變量適合在在多線程的情況下共享。
#include <pthread.h>
#include <iostream>
int errorCode = 0;
void* MaySetErr(void* input)
{
if (*(int *)input == 1)
errorCode = 1;
else if (*(int *)input == 2)
errorCode = -1;
else
errorCode = 0;
}
int main()
{
int input_a = 1;
int input_b = 2;
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, &MaySetErr, &input_a);
pthread_create(&thread2, NULL, &MaySetErr, &input_b);
pthread_join(thread2, NULL);
pthread_join(thread1, NULL);
std::cout << errorCode << std::endl;
return 0;
}
errorCode 值無(wú)法確定。因?yàn)?線程1 和 線程2 的執(zhí)行順序是無(wú)法確定的。
實(shí)際上,本例中 errorCode 即是 POSIX 標(biāo)準(zhǔn)中的錯(cuò)誤全局變量 errno 在多線程情況下遇到問(wèn)題的一個(gè)簡(jiǎn)化。
一旦 errno 在線程間共享時(shí),則一些程序中允許的錯(cuò)誤將會(huì)被隱藏不報(bào)。而解決方法就是為每個(gè)線程指派一個(gè)全局的 errno,即 TLS 化 的 errno。
不同的編譯器有不同的 TLS 標(biāo)準(zhǔn)。
g++/clang++/xlc++ 可以看到如下語(yǔ)法:
__thread int errCode;
每個(gè)線程擁有獨(dú)立的 errCode 的拷貝,一個(gè)線程中的 errCode 的讀寫并不會(huì)影響另一個(gè)線程中的 errCode。
C++11 對(duì) TLS 標(biāo)準(zhǔn)做了統(tǒng)一的規(guī)定。
int thread_local errCode;
對(duì) thread_local 變量地址取值(&),也只能獲得當(dāng)前現(xiàn)場(chǎng)中 TLS 變量的地址值。