前言
在C++11多線程編程中,thread_local 這個關鍵詞在一些特定場合挺有用的。什麼是thread_local,關於thread_local。
thread_specific_ptr代表了一個全局的變量,而在每個線程中都各自new一個線程本地的對象交給它進行管理,這樣,各個線程就可以各自獨立地訪問這個全局變量的本地存儲版本,線程之間就不會因爲訪問同一全局對象而引起資源競爭導致性能下降。而線程結束時,這個資源會被自動釋放。
C++11的thread_local來自於boost中的thread_specific_ptr
thread_local使用場景
dre是一個全局的default_random_engine對象(全局對象可以是C風格的extern,也可是C++風格的static,如果在同一個源文件中,則在“代碼的上面”)。同時開啓多個線程運行,每個線程都需要使用這個全局的dre對象,不同的線程對dre設置不同的seed。但是,又不能讓所有線程同時訪問同一個dre,這樣dre的seed變來變去,而且無法得到想要的隨機值序列。
此時有2個解決方案:
- 改變聲明dre的地方,把dre從全局對象變爲線程的局部變量(比如一個函數中)。在線程裏面,再通過參數的傳遞,把dre傳到需要它的地方。
- 聲明dre的地方不變,依然是全局,只要加一個thread_local關鍵詞,其他什麼都不用改。
方案1很醜陋,方案2很優雅。
talk is cheap, show me the code
#include <iostream>
#include <future>
#include <vector>
#include <chrono>
#include <random>
using namespace std;
using namespace chrono;
thread_local default_random_engine dre;
vector<int> test_dre(int seed)
{
dre.seed(seed);
int vecSize = 10;
vector<int> temp(vecSize);
for (int i = 0; i < vecSize; ++i)
{
temp[i] = dre();
this_thread::sleep_for(milliseconds(100));
}
return temp;
}
bool equal(const vector<int> &v1, const vector<int> &v2)
{
int size1 = v1.size();
int size2 = v2.size();
if (size1 != size2)
return false;
for (int i = 0; i < size1; ++i)
{
if (v1[i] != v2[i])
return false;
}
return true;
}
int main()
{
int numThread = 2;
using returnType = vector<int>;
future<returnType> future1 = async(test_dre, 0);
returnType result2 = test_dre(0);
returnType result1 = future1.get();
if (equal(result1, result2))
cout << "they are equal" << endl;
else
cout << "they are not equal" << endl;
system("pause");
return 0;
}
程序運行結果:
they are equal
分析:兩個線程運行的時候,擁有不同的dre。但是寫代碼的時候,卻是相同的dre。這就很爽了!
如果把thread_local這個關鍵詞註釋掉,那麼兩個線程就會發生data race。運行結果是:
they are not equal