[英]Why may thread_local not be applied to non-static data members and how to implement thread-local non-static data members?
為什么thread_local
不能應用於非靜態數據成員? 這個問題的接受答案是:“制作非靜態結構或類成員線程本地沒有意義。” 老實說,我看到很多很好的理由讓非靜態數據成員成為線程本地的。
假設我們有一些ComputeEngine
,其成員函數computeSomething
連續多次調用。 成員函數內部的一些工作可以並行完成。 為此,每個線程都需要某種ComputeHelper
,例如,它提供輔助數據結構。 所以我們真正想要的是以下內容:
class ComputeEngine {
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
return sum;
}
private:
thread_local ComputeHelper helper;
};
不幸的是,這段代碼無法編譯。 我們可以做的是:
class ComputeEngine {
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel
{
ComputeHelper helper;
#pragma omp for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
}
return sum;
}
};
但是,這將在連續調用computeSomething
之間構造和銷毀ComputeHelper
。 假設構造ComputeHelper
很昂貴(例如,由於大型向量的分配和初始化),我們可能希望在連續調用之間重用ComputeHelper
。 這引出了以下樣板方法:
class ComputeEngine {
struct ThreadLocalStorage {
ComputeHelper helper;
};
public:
int computeSomething(Args args) {
int sum = 0;
#pragma omp parallel
{
ComputeHelper &helper = tls[omp_get_thread_num()].helper;
#pragma omp for reduction(+:sum)
for (int i = 0; i < MAX; ++i) {
// ...
helper.xxx();
// ...
}
}
return sum;
}
private:
std::vector<ThreadLocalStorage> tls;
};
thread_local
不能應用於非靜態數據成員? 這種限制背后的理由是什么? 我沒有給出線程局部非靜態數據成員完美意義的好例子嗎? 至於為什么thread_local
不能應用於非靜態數據成員,它會破壞這些成員的通常排序保證。 也就是說,單個public/private/protected
組中的數據成員必須按照與類聲明中相同的順序布置在內存中。 更不用說如果在堆棧上分配一個類會發生什么 - TLS成員不會進入堆棧。
至於如何解決這個問題,我建議使用boost::thread_specific_ptr
。 您可以將其中一個放入您的課程中,並獲得您想要的行為。
線程本地存儲通常的工作方式是在線程特定的數據結構中獲得一個指針(例如Windows中的TEB)
只要所有線程局部變量都是靜態的,編譯器就可以輕松計算這些字段的大小,分配大小的結構並為每個字段分配一個靜態偏移量。
一旦你允許非靜態字段,這整個方案變得更加復雜 - 解決它的一種方法是一個額外的間接級別並在每個類中存儲索引(現在你在類中隱藏字段,而不是意外)。
他們顯然決定讓每個應用程序根據需要處理它,而不是在實現者身上提升這種方案的復雜性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.