# Write atomicity (multi-copy atomicity)

Write atomicity is a property of a cache-coherence protocol: a write only becomes observable once every cached copy of that cache line has acknowledged it, and after that point the old value can no longer be read anywhere. The literature also calls it store atomicity or multi-copy atomicity (MCA). Adve and Gharachorloo's definition prohibits a read from returning a newly written value until all cached copies have acknowledged the invalidations or updates the write generated.

Coherence protocols work per cache line (usually 64 bytes), not per address, which is also the reason two unrelated atomics on one line contend in [[false-sharing-alignment-128]].

## The three variants

MCA is the strict form: no processor sees the write early, including the one that made it.

Other-multi-copy atomicity (oMCA), also called read-own-write-early MCA (rMCA) in academic papers, lets the writing processor read its own write early, typically by forwarding from its store buffer, while still hiding it from everyone else until it is globally visible. ARM's manuals popularized the oMCA term.

Non-multi-copy atomicity (nMCA) lets other processors observe a write before all copies are invalidated.

According to the survey in [[shared-memory-consistency-causality]], x86 and x86-64, ARMv8-A (2017 revision), RISC-V, SPARC v9 and IBM z/Architecture are MCA or oMCA; IBM Power, ARMv7, Itanium and NVIDIA's PTX GPU are nMCA. Intel's Iris Pro 650 GPU has shown nMCA behaviour in memory-model tests. Vendor documentation is rarely direct about any of this, which is why researchers built systematic litmus tests (herdtools) to observe what hardware actually does.

## Why it matters

Under write atomicity, every externally observable reordering of memory operations is a processor-local effect: out-of-order execution and store buffering within one processor, not writes arriving at different processors in different orders. That removes a whole class of synchronization problems. Without it, restoring atomicity when an algorithm needs it becomes the reader's job, and the ways to do that are either slow or subtle.

MCA doesn't mean the hardware underneath is conservative. Architectures that guarantee it may be just as permissive internally and use speculation to cancel work whenever a violation would become visible, at the cost of mis-speculation flushes and tail latency. ARM worked on an nMCA model for ARMv8 (the Flowing Model) before requiring MCA architecturally. Itanium went the other way: general stores were not write-atomic, but dedicated instructions like `st.rel` were, so only the synchronization variables paid for it.

## In language memory models

The C++11 memory model, which C, Rust, Odin and LLVM-based languages adopted in some form, deliberately doesn't require write atomicity, so it can be implemented efficiently on nMCA hardware. The cost has been a series of specification problems: the Power and ARMv7 compiler mappings were found to violate the model in 2016 and 2017, and the C++20 repair made some mappings inefficient on x86. Java's `volatile` and Golang's `sync/atomic` only expose operations that implicitly require write atomicity, which keeps their models simpler. A [[data-race]] is the ordinary way a program opens a side channel onto a missing guarantee, which is part of why languages leave data races undefined.

## Related

- [[shared-memory-consistency-causality]] - a virtual nMCA machine built up to each ordering guarantee
- [[false-sharing-alignment-128]] - cache-line coherence traffic measured from the software side
- [[data-race]] - the program-level condition under which weaker hardware ordering stays hidden
- [[art-of-multiprocessor-programming]] - the algorithms whose correctness depends on these guarantees
