繁体   English   中英

如何为每个实例拥有非静态线程局部变量

[英]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>的变体。 (您可以编写一个类来包装它并使用互斥锁保护映射。)

另一个最初有吸引力的选项是Athread_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_getspecificpthread_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM