3

I was going through some problems with my atomic container and saw this link.

Is there a reason why std::atomic isn't copy-constructable? The solution seems to be this where they just pass the T value to the non-atomic constructor with the atomic load function (if I'm not mistaken).

So in general, is this copy constructor thread safe?

template<typename T>
struct MobileAtomic
{
    std::atomic<T> atomic;

    explicit MobileAtomic(std::atomic<T> const& a) : atomic(a.load()) {}

};
Community
  • 1
  • 1
JohnJohn
  • 325
  • 1
  • 6
  • 17
  • It's unclear whether this code achieves anything sensible. Atomics serve a very specific purpose, and it generally doesn't make sense to copy them. – Kerrek SB Jan 06 '15 at 00:21
  • 2
    As an analogy: An atomic int is much closer to a mutex or semaphore than to an integer. You may want to query the current state of the semaphore (which corresponds to an atomic load), but it makes no sense to copy the semaphore itself. It's a synchronisation mechanism, and making a copy if it is not sensible. – Kerrek SB Jan 06 '15 at 00:24
  • 2
    It's also not clear to me what it would mean for a "constructor to be thread-safe". Who's constructing what in a shared way? – Kerrek SB Jan 06 '15 at 00:32
  • Well if you are to return an atomic variable by value in a function, it implicitly tries to call the copy constructor I think. Compiler gives me an error that points to this constructor declaration `atomic& operator=(const atomic&) = delete;` which is basically prohibited by C++. I guess returning a reference to the variable will do the same thing but I'm not sure. – JohnJohn Jan 06 '15 at 01:54
  • 1
    It makes absolutely no sense for a function to return an atomic variable. Just like it makes no sense for a function to return a mutex. – Kerrek SB Jan 06 '15 at 09:19

1 Answers1

5

Is there a reason why std::atomic isn't copy-constructable?

Yes.

When you are asking for a copy constructible atomic, you're asking for the "normal" rules of single-threaded sequential consistency to apply to a variable that doesn't follow those rules.

In essence, there is no generalized solution.

By using the constructor you show in the question, you sacrifice a deterministic outcome in that you have no guarantee that the source and destination objects are equivalent after construction is complete.

Michael Gazonda
  • 2,720
  • 1
  • 17
  • 33
  • Seems to me I have only two options: I can only return the value of the atomic variable by value (which might change by another thread until the value is assigned by the caller = race), or to return a reference to the atomic variable (which is a variable that I don't want to expose). I guess my best option is to return a const reference which I haven't tried yet. – JohnJohn Jan 06 '15 at 02:02
  • @JohnJohn Another option is to lock the variable with a mutex for the duration of reading. – Michael Gazonda Jan 06 '15 at 02:07
  • 1
    @JohnJohn: You may not realize it, but **as soon as you make a copy**, the value of the original object can diverge from the value of the copy. that's not a race condition. That is the normal behavior when you have two variables. If you logically have one value, you should have one object. – MSalters Jan 06 '15 at 08:08
  • @JohnJohn I have written lots of concurrent lock free code in different languages and I can't think of a single example where I'd have wanted to copy an atomic variable. You should probably ask a question about what you're really trying to do and see if there's not a better way to solve this. – Voo Jan 06 '15 at 17:20
  • @Voo an example I've been working on is `std::atomic foo` where foo may change what it points to, and I have separate mechanisms for maintaining the lifetime and dealing concurrency of that data pointed to by `foo`. The case would be handled by an atomic shared_ptr, but I'd like to stick to standard library solutions (of which no atomic shared ptr exists). – Noah Watkins Jul 03 '17 at 04:15