Katkat

C++ Atomics, Memory Ordering, and Safe Publication

MillenniumSoftware Engineer · Onsite

Last 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?