A single producer writes fixed-size records into a lock-free ring read by one consumer. Give the memory ordering that makes it correct on a weakly ordered machine, and the specific corruption that appears if both indices are plain non-atomic loads and stores.

A single producer writes fixed-size records into a lock-free ring read by one consumer. Give the memory ordering that makes it correct on a weakly ordered machine, and the specific corruption that appears if both indices are plain non-atomic loads and stores.

Approach: Separate the record write from the index publication, then ask what the consumer must observe before it is allowed to read the record.

The producer writes the record then publishes the write index with a release store, and the consumer reads the index with an acquire load before reading the record, which is what makes the record visible before the index that advertises it. Release and acquire form the pairing: everything the producer wrote before the release store is guaranteed visible to any thread that observes that store through an acquire load. Without it a weakly ordered machine is free to make the index update visible before the record bytes, so the consumer sees a slot advertised as full and reads whatever was in it, which is either the previous generation's data or a half-written record with some fields new and some old. That is a torn read, and it is worse than a crash because the values are plausible: a price from one update paired with a size from another produces an order that looks valid. Plain non-atomic accesses are also a data race, so the compiler may hoist the index load out of the loop and spin forever on a stale value, or split a 64-bit store into two on a 32-bit target. On x86 the hardware already orders stores, so the bug hides in testing and appears on a weakly ordered processor. The consumer's index needs the same treatment in reverse so the producer never overwrites a slot the consumer is reading.

Follow-up: You want the producer to never block when the ring is full and to overwrite instead. What does the consumer need in each record to detect that it was lapped?

Key concepts: release store, acquire load, memory ordering, torn read.