[英]Why may thread_local not be applied to non-static data members and how to implement thread-local non-static data members?
[英]How can I have non-static thread-local variable for each instance
問題本身:
class B{/*...*/};
class A {
/* members */
NON-static thread_local B var; // and a thread_local variable here
ret_t method(/* args */);
};
我希望var
獨立存在每個線程和每個實例。
更大的(完整的)問題:
A
實例是跨線程共享的。 B 是調用A::method
所必需的一些資源,並且它必須獨立於線程以避免競爭條件(即A::method
必須對var
具有“寫訪問權限”)。 並且對於B
的不同實例,對應的B
是不同A
。
我想出的一種不太令人滿意的方法是使用一些容器(比如std::unordered_map<THREAD_IDENTIFIER_TYPE, B>
)來存儲每個實例的每個thread
對應的每個var
。 然而,這既不限制跨線程訪問var
也不阻止整個容器被修改。 (所以這需要開發人員足夠小心才能編寫安全的代碼。)
我在 SO 上看到了一些關於 java ThreadLocal 關鍵字(?)的帖子,但它們似乎都沒有提供真正有效的想法。 有什么建議嗎?
你不能有一個非靜態成員聲明thread_local
。 請參閱cppreference 。 特別是:
thread_local
關鍵字只允許用於在命名空間范圍內聲明的對象、在塊范圍內聲明的對象和靜態數據成員。
如果您不想使用 pthreads(在 Windows 上很棘手),那么某些容器是您唯一的選擇。
一種選擇是std::unordered_map<THREAD_IDENTIFIER_TYPE, B>
的變體。 (您可以編寫一個類來包裝它並使用互斥鎖保護映射。)
另一個最初有吸引力的選項是A
的thread_local
靜態成員,它將A*
映射到B
將避免對鎖的任何需要。
class A {
static thread_local std::unordered_map<A*, B> s_B;
....
};
用法:
void A::foo() {
B& b = s_B[this]; // B needs to be default constructable.
...
問題是您需要某種方法來從s_B
映射中刪除元素。 如果A
對象實際上被鎖定到特定線程,或者如果您有某種方法可以調用另一個線程上的函數,這並不是什么大問題——但這也不是完全微不足道的。 (您可能會發現對A
使用唯一標識符更安全,它是一個遞增的 64 位計數器 - 這樣在銷毀A
對象和從所有映射中刪除B
的消息之間重用標識符的風險要小得多正在處理。)
如果您願意使用tbb (即使是由英特爾免費提供的),您也可以使用他們的tbb::enumerable_thread_specific<T>
模板類(本質上類似於std::unordered_map<thread_id,T>
但無鎖,我明白)。 由於A
在線程之間共享,因此每個A
實例都需要一個這樣的容器,但似乎B
更好地聲明為嵌套類型。 例如
class A
{
struct B
{
B(const A*);
void call(/* args */);
};
tbb::enumerable_thread_specific<B> tB ([&]()->B { return {this}; } );
void method(/* args */)
{
tB.local().call(/* args */); // lazily creates threadlocal B if required.
}
/* ... */
};
在可用的情況下,您可以將pthread
-functions pthread_getspecific
和pthread_setspecific
用於 getter 和 setter:
#include <pthread.h>
class A {
private:
#define varKey 100L
public:
int getVar() {
void *mem = pthread_getspecific(varKey);
if(mem)
return *((int*)mem);
else
return 0;
}
void setVar(int val) {
void *mem = malloc(sizeof(int));
*((int*)mem)=val;
pthread_setspecific(varKey, mem);
}
~A() {
void *mem = pthread_getspecific(varKey);
if (mem)
free(mem);
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.