Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nonlocking Way to Copy Atomics in Copy Constructor

I am writing a copy constructor for a data structure which needs to copy two std::atomic<T> members into a new object. While the process doesn't necessarily have to be atomic in my use-case, I would prefer to have the most correct solution possible.

I am aware that the copy constructor is explicitly deleted with std::atomic<T> so as to force users to use the atomic interface.

atomic(const atomic&) = delete;

What I am currently I am doing something like this:

SomeObject(const SomeObject& other): 
   _atomic1(other._atomic1.load()),            
   _atomic2(other._atomic2.load()) {
...
}

I do not believe this operation is atomic, nor do I know a way to make is so (without locks).

Is there a way to copy these values atomically (without locks)?

like image 659
Don Scott Avatar asked Sep 27 '22 05:09

Don Scott


1 Answers

The only way is to make a trivially copyable struct S containing two Ts and use std::atomic<S>.

Note that this only works if you've been using this S from the start - there is no way to atomically load two separate atomics without locks.

So instead of:

struct SomeObject {
    SomeObject(const SomeObject& other) : i(other.i.load()), j(other.j.load()) { }
    std::atomic<int> i, j;
};

Do this:

struct SomeObject {
    SomeObject(const SomeObject& other) : data(other.data.load()) { }
    struct Data { int i, j; };
    std::atomic<Data> data;
};

Note that this might (probably will) still use locks internally. Use is_lock_free to check if it does.

like image 175
orlp Avatar answered Sep 30 '22 08:09

orlp