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的
- 命名空間下的全局變量
- 類的static成員變量
- 本地變量
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
}
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個問題需要考慮:
- 各線程的thread_local變量是如何初始化的
- 各線程的thread_local變量在初始化之后擁有怎樣的生命周期,特別是被聲明為thread_local的本地變量(local variables)
下面的代碼可以幫助回答這2個問題,我的測試環境是vs2015。
輸出的前3行打印能幫助解答thread_local變量是如何初始化的,可以看到每個線程都會進行一次初始化,例子中的g_n在主線程中最早被初始化為1,隨后被修改為2和3,但這些修改操作並不影響g_n在線程t2和t3中的初始值(值為1),雖然t2和t3線程啟動的時候主線程中的變量值已經被更新為3,所以主線程、thread1、thread2打印結果分別為3,2,2。
#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;
}
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值是每次運行時變的):
id=8004, n=3
id=8008, n=2id=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