Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
446 views
in Technique[技术] by (71.8m points)

c++ - How can I have non-static thread-local variable for each instance

The problem itself:

class B{/*...*/};
class A {
    /* members */
    NON-static thread_local B var; // and a thread_local variable here
    ret_t method(/* args */);
};

I want var to exist independently each thread and each instance.

The larger (complete) problem:

Instances of A are shared across threads. B is some resource necessary to call A::method, and it must be independent with respect to threads to avoid race condition (that is, A::method must have "write access" to var). And the corresponding B are different for different instances of A.

One not fully satisfactory approach I came up with is to have some container (say std::unordered_map<THREAD_IDENTIFIER_TYPE, B>) to store each var corresponding to each thread per instance. However, this neither limit access to vars across threads nor prevent the whole container from being modified. (So that require developer to be careful enough to write safe code.)


I've seen a few post on java ThreadLocal keyword(?) on SO, but none of them seem to provide idea that really works. Any suggestion?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can't have a non-static member declared thread_local. See cppreference. In particular:

the thread_local keyword is only allowed for objects declared at namespace scope, objects declared at block scope, and static data members.

If you don't want to use pthreads (tricky on Windows), some container is your only option.

One choice is a variant of std::unordered_map<THREAD_IDENTIFIER_TYPE, B>. (You could write a class to wrap it and protect the map with a mutex.)

Another initially attractive option is a thread_local static member of A which maps A* to B will avoid any need for locks.

class A {
    static thread_local std::unordered_map<A*, B> s_B;
    ....
};

usage:

void A::foo() {
    B& b = s_B[this];  // B needs to be default constructable.
    ...

The catch is that you need some way to remove elements from the s_B map. That's not too much of a problem if A objects are actually locked to a particular thread, or if you have some way to invoke functions on another thread - but it's not entirely trivial either. (You may find it safer to use a unique identifier for A which is an incrementing 64-bit counter - that way there is much less risk of the identifier being reused between destroying the A object and the message to remove the B from all the maps being processed.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...