Site Tools


wiki:hazard-pointer

Hazard pointer

A hazard pointer is a mechanism for safely reclaiming memory in lock-free data structures, solving the problem that comes up in Lock-free queue and similar structures: a thread can't just free() a node the moment it unlinks it, because another thread might have already loaded a pointer to that node and be about to dereference it. Freeing too early lets that other thread read (or write) memory that's been given back to the allocator, which is exactly the setup for the ABA problem and for outright use-after-free crashes.

The mechanism

Before dereferencing a pointer obtained from a shared structure, a thread publishes it into a well-known hazard pointer slot, one of a small, fixed number of slots per thread, visible to all other threads. A thread that wants to reclaim a node first scans every other thread's hazard pointer slots; if no one has published that address, it's safe to free.

_Atomic(struct node *) hazard[MAX_THREADS];
 
void *safe_read(_Atomic(struct node *) *shared_ptr, int my_slot) {
    struct node *p;
    do {
        p = atomic_load(shared_ptr);
        atomic_store(&hazard[my_slot], p);   // publish before use
    } while (p != atomic_load(shared_ptr));   // re-check: shared_ptr may have changed
    return p;
}
 
void retire(struct node *p) {
    /* only free p once no hazard[] slot anywhere holds it */
    if (!any_hazard_matches(p)) {
        free(p);
    } else {
        add_to_retire_list(p);   // try again later
    }
}

The re-check after publishing matters: without it, shared_ptr could change (and the old node get freed) in the gap between reading it and publishing it as a hazard, leaving the publish too late to protect anything.

Cost and comparison to RCU

Hazard pointers require every read to do real work: publish, re-verify, and later clear the slot, plus every reclaim has to scan every thread's slots. This is more overhead per read than RCU's plain pointer load, but hazard pointers reclaim memory much more promptly (as soon as no thread's slots reference a node, rather than waiting for a whole grace period across all CPUs), which matters when memory pressure or reclaim latency is a concern. The two techniques solve the same problem, safe reclamation under concurrent lock-free access, with a fundamentally different cost tradeoff: RCU makes reads free and reclamation coarse-grained; hazard pointers make reads slightly more expensive but reclamation fine-grained and prompt.

wiki/hazard-pointer.md · Last modified: by 127.0.0.1