Reputation: 305
Consider this problem: I have an atomic_ref
of a user type. I want to concurrently accessing its member functions. See code below:
struct A{
int counter=0;
int add(){
++counter;
return counter;
};
};
int main() {
A a;
std::atomic_ref<A> ra{a};
std::vector<std::thread> v;
for(int i=0;i<1000;++i){
v.emplace_back([&ra]{ra.load().add();});
};
for(auto & t: v){t.join();};
std::cout<<a.counter<<std::endl;
};
Final output is 0
because load()
returns a copy. Is there any other way to reach the correct result by atomic_ref
?
And I also want to ask that, if we have an atomic_ref<T*>
, can we use load()
to accessing member functions, e.g. ra.load()->add()
. Is it safe? Code will become like this:
struct A{
int counter=0;
int add(){
++counter;
return counter;
};
};
int main() {
A* a=new A;
std::atomic_ref<A*> ra{a};
std::vector<std::thread> v;
for(int i=0;i<1000;++i){
v.emplace_back([&ra]{ra.load()->add();}); //Accessing member functions.
};
for(auto & t: v){t.join();};
std::cout<<a->counter<<std::endl;
};
In my test, it's indeed 1000
which is correct.
Upvotes: 0
Views: 361
Reputation: 473212
Atomics are not magical. They only affect the loading and accessing of the reference itself, not of anything accessed though the reference.
Upvotes: 2