
Gottlob Frege wrote:
Good question. I think the question at hand (or in my mind) is whether atomic<Foo>, implemented with an internal mutex, is valid.
It is.
Given
A) the reordering of
m1.lock(); x1++; m1.unlock();
m2.lock(); x2++; m2.unlock();
to
m1.lock(); m2.lock(); x2++; x1++; m1.unlock(); m2.unlock();
This reordering is invalid, by the way, which is why Alexander has been careful to use "multi_lock". If you add a second example that locks/unlocks m2 first, then m1, and reorder it in the same way, the reordered example can deadlock, and the original cannot. It somewhat depends on what you mean by reordering though. It's probably true that an observer thread can see the memory effects of the operations in the order m1.lock/m2.lock/x2++/x1++ by using acquire loads (or maybe try_lock, assuming that it doesn't fail spuriously, which it's allowed to do) on the control variables of m1 and m2 and on x1 and x2, but this is not the same as reordering on the thread 1's side, whether by the compiler or by the hardware. Either way, the C++MM doesn't "think" in terms of reorderings, it specifies behavior of multithreaded programs. If you really think that atomic<Foo>, implemented with a mutex, is not sequentially consistent, there must exist an example (a multithreaded program) containing atomic<Foo> for which the memory model allows an outcome which is not SC.