When should Rust atomics replace a Mutex, and how do orderings work?
Lock-free costs and hardware reordering.
Atomics replace mutexes for counters; Relaxed is atomicity only, SeqCst adds global order, weaker ones skip fences on ARM.
Atomics as a blind faster Mutex.
WHAT THIS TESTS: This question probes whether you understand the fundamental trade-off between mutual exclusion and lock-free concurrency, and whether you can reason about the C++20-derived memory model that Rust inherits. A senior candidate should demonstrate that atomics are not just faster mutexes but a different synchronization primitive with distinct correctness constraints. The interviewer wants to see awareness of compiler reordering, hardware cache coherence, and how memory orderings map to actual CPU fence instructions.
A GOOD ANSWER COVERS: First, the scenario distinction: atomics excel for simple shared state like counters, flags, or producer-consumer indices where a Mutex would introduce unnecessary kernel-level contention, context switches, and cache-line bouncing across cores. Second, the ordering hierarchy: Relaxed guarantees only atomicity and no torn reads or writes but allows compiler and CPU reordering; Acquire and Release establish a happens-before relationship for pairwise synchronization; SeqCst adds a globally consistent total order across all threads but imposes the heaviest synchronization cost. Third, the hardware angle: weaker orderings provide real performance benefits on weakly-ordered architectures like ARM because they avoid expensive memory fence instructions, whereas on strongly-ordered x86 some stronger orderings may be effectively free because the hardware already provides strong guarantees. Fourth, the pragmatic warning that using the wrong ordering is a data race even if it happens to work on x86.
COMMON WRONG ANSWERS: Saying atomics are always faster than a Mutex is wrong because complex invariants still require locking. Defaulting to SeqCst for safety without understanding the cost shows shallow knowledge. Claiming that Relaxed is sufficient for publishing shared data between threads is a serious error that leads to subtle bugs on ARM. Another red flag is ignoring the difference between compiler reordering and hardware reordering, or conflating atomicity with visibility.
LIKELY FOLLOW-UPS: The interviewer may ask you to implement a spinlock using an AtomicBool with Acquire and Release orderings. They might ask why a Relaxed counter can lose increments on some architectures or how to correctly implement a lock-free queue. Another follow-up is asking what happens when you move from x86 to ARM and why code that passed tests on Intel suddenly fails.
ONE CONCRETE EXAMPLE: Consider a multi-threaded metrics collector incrementing a shared request counter. Wrapping a u64 in a Mutex would force every thread to serialize through a single cache line and potentially enter the kernel. Replacing it with an AtomicU64 using Relaxed ordering is safe because the operation is commutative and no other state is being published. However, if the same thread writes a log buffer pointer and then sets a done flag, the flag must use at least Release in the writer and Acquire in the reader to ensure the pointer write is visible before the flag is observed. Using Relaxed for the flag would let the CPU reorder the writes, causing the reader to see a valid flag but a stale pointer.
Read the original → doc.rust-lang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.