Worked examples — Memory consistency models
The scenario matrix
Every litmus test we can face is one row of this table. The goal of the 8 examples below is to fill every cell at least once.
| # | Case class | Concrete question | Models that differ here |
|---|---|---|---|
| A | S→L reorder (store buffer) | Store-Buffering: can both loads read stale 0? | SC=No, TSO/x86=Yes |
| B | S→S reorder | Message-passing flag: can consumer see flag but stale data? | SC/TSO=No, Weak=Yes |
| C | L→L reorder | Load-buffering: can two loads be reordered before their stores? | SC/TSO=No, Weak=Yes |
| D | Degenerate: single core | Does a core ever see its own ops out of order? | All models: No |
| E | Degenerate: no sharing | Two cores, disjoint addresses — any interaction? | All models: No |
| F | Cycle test (proof) | Prove SC forbids the SB bad outcome | SC only |
| G | Multi-copy atomicity (IRIW) | Do two readers agree on the order of two writes? | SC/TSO=Yes agree, POWER/ARM=No |
| H | Limiting case: full fences | Insert MFENCE — does TSO recover SC? |
recovers SC |
| I | Real-world twist | Spin-lock acquire/release correctness | needs acquire/release |
| J | Exam twist: transitivity | WWC / cumulative barriers across 3 cores | Weak needs cumulative fence |
Example A — Store→Load reorder (cell A)
Answer: Yes.
- What: S1 writes
x=1but the value first lands in Core 1's store buffer, not memory. Why this step? TSO's only relaxation is that a store can sit buffered while the core races ahead — this is the S→L cell. - What: L2 reads
y. Memory still holdsy=0(S3 is also stuck in Core 2's buffer). Sor1 = 0. Why: the buffered store on the other core is not yet globally visible. - What: Symmetrically, L4 reads
x=0, sor2 = 0. Why: both cores did the same trick at once — this is the whole point of a store buffer.

Verify: Under SC this is impossible (Example F proves it). Under TSO the two buffered stores plus two early loads give exactly
(r1,r2) = (0,0). This matches the parent's canonical claim. ✅
Example B — Store→Store reorder (cell B)
Answer: Yes — r can be the stale 0.
- What: On weak hardware S1 and S2 have no S→S ordering —
flag=1may reach Core 2 beforedata=42. Why this step? This is the S→S cell; TSO forbids it, ARM does not. - What: Consumer's loop L3 sees
flag==1, exits, then L4 readsdata— butdata=42hasn't propagated yet, sor=0. Why: the two writes traveled independently. - Fix: producer inserts a release fence between S1 and S2; consumer inserts an acquire fence after L3. See Memory Barriers and Fences and C++ Memory Model (acquire-release). Why: a release-acquire pair recreates the S→S / L→L ordering the algorithm needs.
Verify: On TSO/x86 S→S is preserved, so
ris guaranteed42— the pattern works fence-free there. On ARM without fencesr ∈ {0, 42}. Both outcomes are legal on weak, only42on TSO. ✅
Example C — Load→Load reorder (cell C)
Answer: Only on Weak (ARM/POWER); No on SC and TSO.
- What:
r1==1means L1 read the value written by S4.r2==1means L3 read the value written by S2. Why this step? We are asking whether a load can effectively slide after the store below it — the L→S / L→L relaxation. - What: For this to happen, S4 must be visible before L1, and S2 visible before L3 — but program order has L1<S2 and L3<S4. Why: on SC/TSO loads never bypass later stores of the same core, so no core can publish its store before completing its earlier load.
- What: On ARM the load may be delayed / speculated past the store, allowing both
1s. Why: weak models drop L→L and L→S ordering by default.
Verify: SC/TSO table rows both show L→S = ✅, so LB's
(1,1)is impossible there; ARM's row is all ❌ so it is allowed. ✅
Example D — Single core sees itself in order (cell D)
Answer: r = 5, always, on every model.
- What: Even in TSO the store
x=5sits in the buffer, but a later load of the same address checks the buffer first — store forwarding. Why this step? This is the degenerate single-core case; consistency models only govern what other cores see, never a core's view of itself. - What: So L2 sees the freshest value
5regardless of drain timing. Why: every model preserves per-core, per-address program order — that is the Cache Coherence guarantee plus store forwarding, see Store Buffers and Write Buffering.
Verify:
r = 5. No model permitsr = 0here. This is the invariant that keeps single-threaded code correct. ✅
Example E — No sharing, no interaction (cell E)
Answer: (1, 1) on every model.
- What: Each core reads only its own address, which it just wrote. Why this step? With no shared address there is nothing for a consistency model to constrain — it degenerates to two independent single-core programs (cell D twice).
- What: Store forwarding gives each
rits own core's fresh write. Why: cross-core ordering rules never fire when no location is shared.
Verify:
(r1, r2) = (1, 1). Reordering is invisible without sharing. ✅
Example F — Cycle proof: SC forbids SB's bad outcome (cell F)
- What:
r1==0⇒ in the single total order , load L2 (read y) came before store S3 (write y). So . Why this step? SC gives one total order consistent with each program order; a load returning the initial 0 must precede the store that would change it. - What:
r2==0⇒ likewise . - What: Program order forces (Core 1) and (Core 2). Why: SC never reorders a core's own operations.
- What: Chain them: . Why: substitute the four facts head-to-tail.
- What: That says — a cycle. A total order is antisymmetric, so this is a contradiction. ∎

Verify: The dependency graph has a 4-node directed cycle, so no total order exists ⇒ SC forbids
(0,0). This is why store buffers (TSO) are strictly weaker than SC. ✅
Example G — Do two readers agree? IRIW (cell G)
Answer: No on SC and TSO. Yes on POWER/ARM (non-multi-copy-atomic).
- What: The outcome asks whether two independent writes are observed in different orders by different readers. Why this step? This is a stronger property than any single-core reordering — it is about whether a single global store order even exists.
- What: SC/TSO both commit stores to one total store order, so all readers agree ⇒ the outcome is impossible. Why: "single total order" is exactly what SC/TSO promise about stores.
- What: POWER/ARM may propagate
x=1to C3 early whiley=1reaches C4 early — writes are not multi-copy-atomic. Why: weak interconnects deliver writes to different cores at different times.
Verify: SC/TSO forbid the split-observation
(1,0,1,0); POWER/ARM allow it. Recovering agreement on weak hardware needs a cumulative barrier (cell J). ✅
Example H — Limiting case: fences recover SC (cell H)
Answer: No — the fences restore SC for this test.
- What:
MFENCEdrains the store buffer, forcing S1 to become globally visible before L2 executes. Why this step? This is the limiting case: turning the one TSO relaxation (S→L) back on gives full SC ordering locally. See Memory Barriers and Fences and Atomic Operations and Locks. - What: Now at least one store is truly first in the global order, so both loads cannot both read 0 — reuse the cycle argument of Example F.
Why: with S→L re-enforced, the SB ordering graph is acyclic-impossible for
(0,0).
Verify: With fences, TSO's L→L, L→S, S→S, and S→L are all enforced ⇒ table row equals SC ⇒
(0,0)forbidden. The fence is the "dial" from TSO back to SC. ✅
Example I — Real-world twist: a spin-lock (cell I)
Answer: Only if test_and_set has acquire semantics and the release store has release semantics.
- What: A plain load/store lock on ARM lets critical-section reads hoist above the acquire (L→L relaxed) or writes sink below the release (S→S relaxed). Why this step? Without ordering, another thread could observe the "unlocked" state while our writes are still in flight — corrupting shared data.
- What: Acquire = no later op may be reordered before it. Release = no earlier op may be reordered after it. Why: together they form a one-way fence pair that boxes the critical section — exactly the C++ Memory Model (acquire-release) guarantee.
- What: On x86/TSO a
LOCK-prefixed test-and-set already drains the buffer, so the lock works with weaker source annotations. Why: TSO only lacked S→L, which the locked atomic fixes.
Verify: Acquire on lock-in + release on lock-out ⇒ every critical-section op is ordered between them ⇒ no leak. This is the standard correctness proof for mutual exclusion under weak models. ✅
Example J — Exam twist: transitivity / cumulativity (cell J)
Answer: On SC/TSO yes. On plain ARM/POWER, not unless C2's fence is cumulative.
- What:
r1==1means C2 saw C1'sx=1; then C2 publishedy=1;r2==1means C3 saw thaty. Why this step? Intuitively causality should carryx=1along the chain C1→C2→C3. - What: On non-multi-copy-atomic hardware,
x=1may still not have reached C3 even thoughy=1has, sor3can be0. Why: ordinary barriers order only the fencing core's own ops; they don't force previously observed writes to also propagate — that stronger property is cumulativity. - What: A cumulative release fence (e.g. ARM
dmb ish/ release store) forces C1'sx=1to propagate before C2'sy=1, sor3must be1. Why: cumulativity extends the fence's reach to writes the core has read, not just written.
Verify: SC/TSO: single store order ⇒
r3forced to1. Plain weak:r3 ∈ {0,1}. Cumulative fence on C2 ⇒r3 = 1. This is the classic "barriers aren't automatically transitive" exam trap. ✅
Recall Which cell does each example hit?
Example A hits which reordering pair? ::: S→L (store buffer) Example B relaxes which pair, and on which model only? ::: S→S, on Weak/ARM only Example C (Load-Buffering) is impossible on which models? ::: SC and TSO Example F proves impossibility using what graph property? ::: a directed cycle in the memory order IRIW (G) distinguishes which hardware property? ::: multi-copy atomicity (single vs. per-core store propagation) Example H shows a fence dials TSO up to which model? ::: Sequential Consistency (SC) Example J's trap is that ordinary barriers lack what property? ::: cumulativity (transitivity across cores)
Back to Memory consistency models · prerequisite recap: Out-of-Order Execution, Store Buffers and Write Buffering.