A store with std::memory_order_release
to some location can be reordered with a subsequent load from another location with std::memory_order_acquire
.
But can a store with std::memory_order_release
to some location be reordered with a subsequent load from another location with std::memory_order_seq_cst
?
Analogously, can a store with std::memory_order_seq_cst
to a variable be reordered with a subsequent load from another location with std::memory_order_acquire
?
Consider this example:
std::atomic<int> x{0};
std::atomic<int> y{0};
void thread1() {
x.store(std::memory_order_release, 1);
int r1 = y.load(std::memory_order_seq_cst);
std::cout << r1 << std::endl;
}
void thread2() {
y.store(std::memory_order_seq_cst, 1);
int r2 = x.load(std::memory_order_acquire);
std::cout << r2 << std::endl;
}
It is well known (http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/) that if both std::memory_order_seq_cst
were replaced by their release/acquire counterpart the output could be two times "0".
Does the sequential-consistency buy anything in this example or can the output still be two times "0"?
No, the sequential-consistency does not buy anything in this example and the output can still be two times "0".
The only difference between
std::memory_order_seq_cst
andstd::memory_order_acquire/release
is thatstd::memory_order_seq_cst
-stores may not be reordered with subsequentstd::memory_order_seq_cst
-loads to different variables/locations, see Herb Sutter's "atomic<> Weapons" talk. (Of course, it may never happen that stores are reordered with subsequent loads to the same variable.)But, as soon as only one (let alone both) of the memory-orders gets weakened (as is the case in both threads in the example) the StoreLoad reordering may happen. That means, in the example both loads may be reordered before their respective store.
This means that a program that only contains a single
std::memory_order_seq_cst
and otherwise onlystd::memory_order_release/acquire
remains the same program if one were to replace the lonelystd::memory_order_seq_cst
bystd::memory_order_release
(if it is with a store) or astd::memory_order_acquire
(if it is with a load).