![](/img/trans.png)
[英]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.