C++ Atomics, Memory Ordering, and Safe Publication
MillenniumSoftware Engineer · OnsiteLast updated
Understand C++ atomics, relaxed counters, acquire-release publication, lost updates, and when multi-field invariants still require a mutex.
What is an atomic operation in C++, and how is std::atomic different from protecting shared state with a mutex?
Use a shared counter and a producer publishing a payload to a consumer to explain the difference between atomic access and ordering other memory accesses. Explain why a sequence of atomic operations is not automatically one indivisible transaction.
Constraints & Assumptions
- Use the C++ memory model and
std::atomic; do not assume an atomic type is always lock-free. - The counter is used only for counting, with no associated payload that its value publishes.
- In the publication example, one producer initializes a payload once and signals one consumer with an atomic flag. The producer does not modify that payload afterward.
- A hypothetical transfer between two balances requires their combined invariant to be observed consistently.
Clarifying Questions to Ask
- Does this atomic variable only count events, or does it signal that other data is ready?
- Are there multiple writers, and can the payload be reused or changed after publication?
- Is the requirement atomicity of one field or a transaction across several fields?
Hints
Hint 1
Follow the publication edge: An atomic ready flag is useful only if observing it also establishes the required ordering for the ordinary payload accesses.
Follow-up questions
- Why can `counter.store(counter.load() + 1)` lose increments even though both operations are atomic?
- What would need to change if the producer repeatedly overwrote the published payload?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.