Compiler reorders for optimization (register allocation, hoisting).
CPU executes out-of-order and speculatively.
Cache/store buffers delay when a write becomes visible to other cores.
A naive flag like bool ready = true gives no guarantee that the data you wrote before it is visible when another thread sees ready == true. That's the bug acquire-release fixes.
Two friends pass notes. Ravi writes a secret on a paper (the data), then puts a flag up on the mailbox (the atomic). Maya keeps checking the mailbox; the moment she sees the flag up, the rule of this game guarantees the secret is already inside — she'll never open an empty box. "Put the flag up" = release (finish writing first, then signal). "See the flag and open" = acquire (once you see the signal, you may read everything). If they skip these rules (relaxed), Maya might see the flag but open the box before Ravi finished writing — garbage. The flag only works because Maya saw the exact flag Ravi raised — that's "must read the stored value".
What is a data race in C++ and what is its consequence?
Two threads access the same memory location, ≥1 writes, with no happens-before ordering between them. It is undefined behavior.
Define the happens-before relation.
The transitive closure of sequenced-before (intra-thread) and synchronizes-with (cross-thread atomic edges). If A hb B, B sees all of A's side effects.
When does a release-store synchronize-with an acquire-load?
When the acquire-load reads the value that the release-store wrote (or a later value in its release sequence).
What ordering does memory_order_release guarantee?
No memory operation before the store may be reordered after it (downward barrier); its prior writes become visible to a matching acquire.
What ordering does memory_order_acquire guarantee?
No memory operation after the load may be reordered before it (upward barrier); it sees the publisher's writes prior to the release.
What does memory_order_relaxed guarantee?
Atomicity and per-variable modification-order consistency only — NO ordering of other memory, no synchronizes-with edge.
How is seq_cst stronger than acq_rel?
It adds a single global total order that all seq_cst operations agree on, preventing inconsistent observations (e.g. IRIW).
Why must the acquire-load read the stored value to create the edge?
Synchronization follows data flow; if the load read an older value it never observed the release, so it inherits none of the writer's prior work.
In the message-passing example, why is assert(data==42) guaranteed?
data=42 →(seq-before) release-store →(sync-with) acquire-load →(seq-before) assert, forming an hb chain so the reader sees data.
Dekho, modern CPU aur compiler speed ke liye instructions ka order badal dete hain. Ek single thread ke andar ye dikhta nahi, sab sequential lagta hai. Lekin jab do threads same memory share karte hain, tab ek thread doosre thread ki writes ulte order mein dekh sakta hai. C++ ka memory model ek contract hai jo batata hai ki reading thread ko kaunsi writes guaranteed dikhengi. Iska dil hai happens-before relation: agar A happens-before B hai, to B ko A ka sab kuch dikhega.
Acquire-release ek mailbox jaisa socho. Producer pehle data = 42 likhta hai, phir flag uthata hai ready.store(true, release). Release ka matlab: jo bhi maine pehle kiya wo store ke neeche nahi jaa sakta — yaani jab koi flag dekhega, uska saara kaam ready hoga. Consumer ready.load(acquire) karta hai; acquire ka matlab: jo ops baad mein hain wo load ke upar nahi aa sakte. Jab acquire-load wahi value padhta hai jo release-store ne likhi thi, tabhi ek synchronizes-with edge banta hai, aur poora happens-before chain ban jaata hai. Result: assert(data==42) hamesha pass hoga.
Sabse badi galti: log sochte hain "flag ko atomic bana diya, ab sab safe hai". Galat! Atomic sirf us atomic variable ko torn-read se bachata hai. Non-atomic data tabhi safe hai jab acquire/release ne happens-before edge banaya ho. Agar tum relaxed use karoge, koi ordering edge nahi banta — data ki write ready ke baad visible ho sakti hai, ya consumer stale value padh sakta hai, aur assert fail. Yaad rakho: Release neeche barrier (purana past below rakhe), Acquire upar barrier (future above rakhe), aur edge tabhi banta hai jab acquire ne wahi value padhi jo release ne likhi.