Can atomics suffer spurious stores?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Atomic operations can exhibit surprising behavior under contention, but plain atomic stores do not have a spurious success or failure concept. The term spurious usually applies to weak compare-exchange operations. Most confusion comes from retry loops and memory ordering semantics, not from random extra committed stores.
What Spurious Means in Lock-Free Context
In lock-free terminology, spurious failure usually refers to compare_exchange_weak returning false even when values appear unchanged. This is allowed by language memory models to support efficient hardware mappings.
Important distinction:
- plain
storewrites value exactly when invoked compare_exchange_weakmay fail spuriously and require retry
That does not imply phantom writes to shared memory.
This store is deterministic with respect to operation semantics.
Why CAS Retry Loops Feel Like Spurious Stores
In a CAS loop, many attempts may fail before one succeeds. Observing repeated attempts can look like extra writes, but failed attempts do not commit the proposed new value.
Notice that expected can change locally after each failure. Developers sometimes mistake this local variable update for a shared-memory store.
Memory Order Visibility Is Not Spurious Storage
Another source of confusion is delayed visibility between cores. A store can occur on one core and become visible to another core later. That is normal coherence behavior under chosen memory order.
Ordering modes summarize intent:
relaxedgives atomicity onlyreleasepublishes prior writesacquireobserves published writesseq_cstprovides strongest global ordering constraints
Visibility timing differences are expected and do not indicate random stores.
Weak Versus Strong Compare-Exchange
compare_exchange_weak is recommended in retry loops, while compare_exchange_strong is often used for single-shot state transitions.
Strong does not eliminate contention failures from concurrent updates. It only removes allowed spurious failure behavior that weak may exhibit.
Practical Debugging Strategy
If you suspect atomic bugs, instrument retry counts and state transitions in debug builds. Combine that with stress tests under high contention.
Useful checks:
- retry loop iteration distribution
- final state invariants after parallel operations
- consistency between atomic state and protected non-atomic state
Many concurrency bugs attributed to atomics are actually missing synchronization around related non-atomic fields.
Design Guidance for Production Code
Use lock-free techniques only where contention and latency profiles justify complexity. For many workloads, a mutex-based design is easier to verify and maintain.
If you choose atomics:
- document invariants next to code
- justify memory orders explicitly
- keep shared-state model minimal
- add targeted stress tests in CI
Clarity is more valuable than clever one-liners in concurrent code.
Common Pitfalls
Assuming spurious CAS failure means random committed writes leads to wrong diagnosis.
Ignoring that failed CAS updates local expected value can confuse loop logic.
Mixing atomic and non-atomic access to related state without proper synchronization causes undefined behavior.
Overusing seq_cst without need can hurt performance, while underusing ordering can break correctness.
Summary
- Plain atomic stores do not have spurious success or failure behavior.
- Spurious behavior is associated with weak compare-exchange operations.
- CAS retry churn is expected under contention and does not imply phantom commits.
- Memory visibility timing differences are normal under chosen ordering rules.
- Correctness depends on full synchronization design, not atomics in isolation.

