Reclaiming memory: hazard pointers vs epochs
The queue from part one works —
until you try to free a popped node. Who guarantees no other thread still holds
a pointer to it? That's the memory reclamation problem, and it has two classic
answers.
Hazard pointers
Each thread publishes the pointers it's currently dereferencing into a shared, per-thread "hazard" slot. A node can only be freed once no hazard slot references it.
Hazard pointers give tight, predictable memory bounds — at most O(threads × K)
unreclaimed nodes. The cost is a memory fence on every access to publish the
hazard, which hurts read-heavy workloads.
Epoch-based reclamation
Threads advance through global epochs. Retired nodes are stashed in per-epoch bags and only freed once every thread has moved two epochs past the retirement.
1let guard = pin; // enter the current epoch2let shared = self.head.load;3guard.defer_destroy; // freed once all threads advance
Epoch reclamation is what crossbeam-epoch uses under the hood. Pinning is cheap
(a single atomic), which is why it usually wins for general-purpose structures.
Which one?
The short version: epochs for throughput, hazard pointers for bounded memory.