My question is simple: is there any parallel algorithm where using an object of a trivial type T is legal and safe (well defined, guaranteed to work) and using instead an std::atomic<T> object leads to unspecified or undefined behavior? In other words, it is possible for a non atomic type to provide stronger guarantees than an atomic type?

Are all the guarantees of memory visibility valid for atomic object when they are valid for regular objects?

[That would mean that a compiler could treat (relaxed) atomic and non atomic operations the same, simplifying intermediate representation.]

If yes, is that formally provable?

Of course types T such that std::atomic<T> isn't a valid specialization of std::atomic don't count.

1 Answers

selbie On

No scenario in which a non-atomic value has a stronger guarantee when compared to it's atomic equivalent.

The only bad pattern I can think of, is when a developer makes a mistake of assuming that if all members of a data structure are individually thread safe, then the entire data structure is assumed to be thread safe. This would not be a correct assumption.

Consider the following hypothetical:

class Volume
    atomic<int> _width;
    atomic<int> _height;
    atomic<int> _depth;
   int computeValue() {return (_width*_height*_depth);}
   void SetInternals(int w, int h, int d) {_height=h;_width=w;_depth=d;}

Where thread 1 does this:

f->SetInternals(42, 100, 200);

And thread 2 does this at the same time.

int something_important = f->computeValue();

You can see that the value returned by computeValue may be corrupted if both threads execute at the same time.

You can achieve the desired thread safe behavior with a mutex and lock combo instead of atomics:

class Volume
    int _width;
    int _height;
    int _depth;
    mutex _mutex;
   int computeValue() {
        lock_guard<mutex> lck(_mutex);
        int result = _width*_height*_depth;
        return result;
   void SetInternals(int w, int h, int d) {
      lock_guard<mutex> lck(_mutex);