thread_local變量是C++ 11新引入的一種存儲類型。它會影響變量的存儲週期(Storage duration),C++中有4種存儲週期:函數
- automatic
- static
- dynamic
- thread
有且只有thread_local關鍵字修飾的變量具備線程週期(thread duration),這些變量(或者說對象)在線程開始的時候被生成(allocated),在線程結束的時候被銷燬(deallocated)。而且每 一個線程都擁有一個獨立的變量實例(Each thread has its own instance of the object)。thread_local
能夠和static
與 extern
關鍵字聯合使用,這將影響變量的連接屬性(to adjust linkage)。測試
那麼,哪些變量能夠被聲明爲thread_local?如下3類都是ok的ui
- 命名空間下的全局變量
- 類的static成員變量
- 本地變量
下面引用《C++ Concurrency in Action》書中的例子來講明這3種狀況:
thread_local
int x;
//
A thread-local variable at namespace scope
class X
{
static thread_local std::
string s;
//
A thread-local static class data member
};
static thread_local std::
string X::s;
//
The definition of X::s is required
void foo()
{
thread_local std::vector<
int> v;
//
A thread-local local variable
}
既然每一個線程都擁有一份獨立的thread_local變量,那麼就有2個問題須要考慮:this
- 各線程的thread_local變量是如何初始化的
- 各線程的thread_local變量在初始化以後擁有怎樣的生命週期,特別是被聲明爲thread_local的本地變量(local variables)
下面的代碼能夠幫助回答這2個問題,個人測試環境是vs2015。spa
輸出的前3行打印能幫助解答thread_local變量是如何初始化的,能夠看到每一個線程都會進行一次初始化,例子中的g_n在主線程中最先被初始化爲1,隨後被修改成2和3,但這些修改操做並不影響g_n在線程t2和t3中的初始值(值爲1),雖然t2和t3線程啓動的時候主線程中的變量值已經被更新爲3,因此主線程、thread一、thread2打印結果分別爲3,2,2。
線程
後6行打印說明了一個事實,聲明爲thread_local的本地變量在線程中是持續存在的,不一樣於普通臨時變量的生命週期,它具備static變量同樣的初始化特徵和生命週期,雖然它並無被聲明爲static。例子中foo函數中的thread_local變量 i 在每一個線程第一次執行到的時候初始化,在每一個線程各自累加,在線程結束時釋放。
#include <thread>
thread_local
int g_n =
1;
void f()
{
g_n++;
printf(
"
id=%d, n=%d\n
", std::this_thread::get_id(),g_n);
}
void foo()
{
thread_local
int i=
0;
printf(
"
id=%d, n=%d\n
", std::this_thread::get_id(), i);
i++;
}
void f2()
{
foo();
foo();
}
int main()
{
g_n++;
f();
std::thread t1(f);
std::thread t2(f);
t1.join();
t2.join();
f2();
std::thread t4(f2);
std::thread t5(f2);
t4.join();
t5.join();
return
0;
}
輸出(id值是每次運行時變的):
code
id=8004, n=3對象
id=8008, n=2 id=8012, n=2 id=8004, n=0 id=8004, n=1 id=8016, n=0 id=8016, n=1 id=8020, n=0 id=8020, n=1