TRT
Sign in
hardExpertconcept

Why can't a lock-free data structure immediately free a node after CAS unlinking, and how do EBR and Hazard Pointers solve it?

Compare Epoch-Based Reclamation (EBR / crossbeam-epoch, grace periods) against Hazard Pointers (bounded memory under stalled threads) for safe lock-free deallocation.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read
Learn it firstMemory reclamationPro — members onlyA lock-free structure can outlive the thread that is reading it: another thread removes a node while the reader is descheduled, and freeing it then is a use-after-free. Hazard pointers, epochs, RCU and garbage collection each answer when a free is safe.

A strong answer

When answering In a lock-free data structure without garbage collection (C, C++, Rust), why can't you immediately free(node) after unlinking it via CAS, and how do Epoch-Based Reclamation and Hazard Pointers solve it?, start from the hardware and runtime invariants taught in Memory reclamation. Compare Epoch-Based Reclamation (EBR / crossbeam-epoch, grace periods) against Hazard Pointers (bounded memory under stalled threads) for safe lock-free deallocation.

First, walk the interviewer through the concrete physical mechanism: on modern multi-core CPUs, memory is transferred in 64-byte cache lines governed by the MESI cache-coherency protocol, where an L1 cache hit costs roughly ~1 ns (4 cycles), an L2 hit costs ~4 ns, an L3 hit costs ~12 ns, and a main-memory DRAM fetch or cross-socket cache-line invalidation costs ~65–100 ns (over 200 cycles). Whenever an algorithm chases scattered pointers, triggers branch mispredictions (~15–20 cycle pipeline flush), or contends on a shared cache line via atomic Read-Modify-Write operations, the CPU's out-of-order execution engine stalls waiting on memory subsystems rather than arithmetic ALUs.

Second, state the exact correctness and progress guarantees: distinguish clearly between blocking synchronization (where a preempted lock holder stalls all waiters) and non-blocking / lock-free synchronization (where at least one thread makes system-wide progress in a finite number of steps via atomic Compare-And-Swap loops, paired with explicit memory ordering and safe reclamation). Always quantify both the asymptotic bound and the cache-line / memory-bandwidth constant factor.

What the interviewer is listening for

  • Hardware-grounded mechanics: Citing concrete 64-byte cache line behavior, MESI invalidation traffic, branch predictor pipelines, or atomic memory ordering (acquire/release vs seq_cst) rather than hand-waving "it's faster".
  • Exact correctness invariant: Explaining the exact race window (such as ABA recycling or use-after-free during concurrent readers) and how the mechanism closes it.
  • Production trade-offs: Knowing when a simpler contiguous array, sharded lock, or Epoch-Based Reclamation beats a complex lock-free pointer structure.

Common mistakes

  • Confusing asymptotic Big-O step counts with actual hardware execution time when pointer-chasing causes an L3/DRAM cache miss on every step.
  • Using memory_order_relaxed when publishing shared pointers or forgetting that unlinking a node in a lock-free structure does not make it safe to free() while concurrent readers are mid-traversal.
  • Benchmarking without preventing compiler dead-code elimination or without inspecting hardware performance counters (perf stat).

This answer walks

Practice follow-ups

  1. 01What happens to memory usage in Epoch-Based Reclamation (EBR) if a single reader thread is preempted by the OS while pinned inside an epoch?
  2. 02Why do Hazard Pointers require a `SeqCst` fence between publishing the hazard pointer and re-validating that the node is still reachable?

Not started

Sign in to save your learning progress.

Sign in to save