I'm trying to get a better understanding of atomic ordering guarantees, but this issue threw me off a bit.
In it, RalfJung and jeehoonkang are discussing this code (I changed AtomicCell to AtomicBool, hopefully that's not significant):
let x = AtomicBool::new(false);
let y = AtomicBool::new(false);
scope(|s| {
// Thread A
s.spawn(|| x.store(true, <ordering>));
// Thread B
s.spawn(|| y.store(true, <ordering>));
// Thread C
s.spawn(|| {
while !x.load(<ordering>) {}
if y.load(<ordering>) { println!("y then x"); }
});
// Thread D
s.spawn(|| {
while !y.load(<ordering>) {}
if x.load(<ordering>) { println!("x then y"); }
});
}).unwrap();
I understand that if <ordering>
is replaced with Release
for stores and Acquire
for loads, then it is not guaranteed that this code will print anything, since thread A/B don't establish an ordering of the stores.
I have a few questions related to this code:
- If we instead use
SeqCst
for all loads and stores, is the code guaranteed to print something? - If
AtomicBool
is replaced withMutex<bool>
, is it guaranteed to print? This one confused me, since in the linked issue Ralf and jeehoonkang seem to believe the answer is no. However I thought the answer was yes, since a Mutex load translates intolock(Acq); read; unlock(Rel)
and I believe the Acq/Rels on every access are enough to guarantee that something prints. I'm mostly basing this intuition on this C++ SO post. - In general, if we have code that uses multiple
AtomicBool
variables and usesSeqCst
for every access to those variables, and then we replaceAtomicBool
withMutex<bool>
, will the new code and old code have exactly the same semantics? (I'm aware that mixingSeqCst
andAcq/Rel
complicates things - I'm just focusing on completelySeqCst
vs completelyAcq/Rel
for now)