Core 0 writes data, then sets a flag. Core 1 waits for the flag, then reads the data. The caches are fully coherent: every core eventually sees every write to the flag and to the data in the right order. And yet, on some processors, core 1 sees the flag set and then reads the old data. No coherence rule was broken. A different rule, one coherence never promised, was.
What does coherence guarantee, and what does it leave to the memory model?
The obvious belief is that coherent caches make shared memory behave like one memory with no caches, so the handoff must work. Coherence promises much less: for each location separately, all cores see writes in one order, and reads return the latest. It says nothing about how writes to the flag are ordered with writes to the data. A core may make its write to the flag visible before its write to the data (a store buffer draining out of order, a write to a line it owns completing before a miss), and coherence is satisfied for both locations.
Coherence | Consistency (memory model) | |
|---|---|---|
Concerns | One location at a time | The order of accesses to different locations |
Guarantees | Single writer or many readers; one order of writes per location; reads see the latest | Which reorderings of loads and stores, across locations, other cores may observe |
Implemented by | The cache coherence protocol | The core's pipeline, store buffer and the barrier instructions, on top of coherence |
Programmer's tool | Nothing to do: it is invisible | Barriers, acquire and release operations, atomics |
The flag-and-data pattern, as a litmus test (initially data = flag = 0):
Core 0 Core 1
data = 42 while (flag == 0) {}
flag = 1 r = data
Can r be 0? TSO (x86): no. Weak models (Arm, Power, RISC-V RVWMO): yes, without barriers.On a weakly ordered processor, a store-store barrier (or a release store) on core 0 and a load-load barrier (or an acquire load) on core 1 restore the intended order. Coherence was working all along; it simply was not the rule that mattered.
Coherence is the foundation: without it, even a single location could have two values, and no memory model could be implemented.
The memory model is built on top: the core decides when its loads and stores become visible, and barriers force it to wait (lesson 7.10).
Interconnect ordering matters too: barriers must also order transactions in the fabric (lesson 7.5), which is why protocols carry ordering and barrier support.
Architecture | Memory model on coherent caches |
|---|---|
x86 | Total Store Order: only a later load may pass an earlier store to a different address (fact T16) |
Arm, Power | Weakly ordered: store buffering, load buffering and message-passing reorderings allowed without barriers (fact T17) |
RISC-V | RVWMO by default, weak; the Ztso extension gives TSO (fact T17) |
Driver code (illustrative) written and tested on x86 set a descriptor's fields, then its "ready" flag, with plain stores. Ported to an Arm system, the device-facing side occasionally read a ready descriptor with stale fields. Caches were coherent throughout; the missing piece was a release barrier between the field writes and the flag write, which TSO had been providing implicitly.
No; that is the memory consistency model's job.
No: TSO keeps stores in order and loads in order, so if core 1 sees flag = 1 it then sees data = 42.
Coherence orders accesses to one location; consistency orders accesses across locations.
A fully coherent system can still break a flag-and-data handoff under a weak memory model.
Barriers and acquire/release operations enforce cross-address order on top of coherence.