簡體   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