Will the other thread even see what I wrote?

Memory Models & Visibility

The advanced core: threads do not necessarily observe memory operations in source order. Happens-before, compiler and CPU reordering, barriers, false sharing, cache coherence traffic, safe publication and why double-checked locking is the canonical cautionary tale.

What a Memory Model Defines▶ lab

Threads do not necessarily observe memory operations in the order your source code wrote them. A memory model is the contract that says which orders are possible — and the language's contract is a different object from the CPU's.

Q · What does a memory model actually define, and why is the language's model not the CPU's?

Happens-Before: The Edge That Makes a Write Visible▶ lab

Happens-before is the relation that answers "will the other thread see it?". It is not about wall-clock time. It is a partial order built from specific paired constructs, and two operations with no path between them are unordered no matter which one ran first.

Q · What actually makes a write in one thread visible to a read in another?

Reordering: The Compiler and the CPU Both Do It▶ lab

Two independent reorderers sit between your source and what another thread observes. Both are allowed to move memory operations as long as *your own thread's* observable behaviour is unchanged. Synchronization is the only thing that constrains either of them.

Q · Who reordered my code — the compiler, the CPU, or neither — and what actually stops it?

Memory Barriers Constrain Ordering, Not Caches▶ lab

A barrier says which of your memory operations may not move across this point. It does not "flush the cache" — caches are already coherent. Getting that distinction right is what separates a correct ordering argument from a plausible-sounding one.

Q · What does a memory barrier actually constrain, and why is "flush the cache" the wrong mental model?

False Sharing: Different Variables, Same Cache Line▶ lab

Two threads update two different counters and never touch each other's data. The counters sit in the same cache line, so every update takes the line away from the other core. Correctness is untouched; the speedup you added a thread for never appears.

Q · Two threads never touch the same variable — why did adding the second thread make it slower?

What a Shared Write Costs▶ lab

Each core has its own cache, and the hardware keeps them consistent for you. That consistency is not free: a location written by many cores generates traffic on every write, which is why one shared counter can cap the throughput of a sixteen-core machine.

Q · What does a shared write actually cost when every core has its own cache?

Safe Publication: Handing Over a Finished Object▶ lab

Making a reference visible is not the same as making the object visible. A reader can hold a perfectly valid pointer to an object whose fields it cannot yet see — a half-constructed object, from the reader's point of view, with no null and no error to warn it.

Q · How does one thread safely hand a newly constructed object to another without the other seeing it half-built?

Double-Checked Locking: The Canonical Cautionary Tale▶ lab

Check without the lock, lock, check again, initialise. It looks like a pure optimization and it is the standard example of why memory-model reasoning matters — the fast path can hand out a reference to an object it cannot see. The fix exists in every language and is different in each.

Q · Why is the obvious "check, lock, check again" lazy initialization broken, and why is the fix language-specific?