Examples/Illustration of Wait-free And Lock-free Algorithms
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Wait-free and lock-free algorithms are both non-blocking, but they do not promise the same thing. The difference is about progress guarantees: lock-free means the system as a whole keeps moving, while wait-free means every individual thread is guaranteed to finish its operation in a bounded number of steps.
The Progress Guarantees Matter More Than The Syntax
These terms are often explained as if they were implementation patterns, but they are really correctness guarantees under contention.
- '
blocking: a stalled thread can prevent others from making progress' - '
lock-free: at least one thread completes an operation in a finite number of steps' - '
wait-free: every thread completes its own operation in a finite number of steps'
That means every wait-free algorithm is also lock-free, but not every lock-free algorithm is wait-free.
A compare-and-swap loop is the usual starting point for lock-free code. If many threads collide, one thread wins and others retry. The overall system progresses, but a particular thread may starve.
A Lock-Free Counter Example
This counter uses an atomic compare-and-swap loop. It is lock-free because if several threads race, one of them will eventually succeed.
Why is this not wait-free? Because one unlucky thread can keep losing the compare-and-swap race and retry forever in theory.
A Simple Wait-Free Illustration
True wait-free data structures are hard to design, but the concept is easier to see with per-thread ownership. If each thread writes only to its own slot, no retries are needed and each operation finishes in a fixed number of steps.
This example is deliberately simple. It illustrates the progress guarantee, not a general-purpose wait-free queue or stack. Each write completes immediately because no other thread can block or force a retry on that slot.
Real Data Structure Examples
Typical lock-free structures include:
- Treiber stack
- Michael and Scott queue
- many atomic counters and work-stealing building blocks
Typical wait-free structures are rarer because the guarantee is stronger and the algorithms are more complex. They often rely on helping mechanisms, bounded retries, versioning, or per-thread descriptors so that a stalled thread cannot delay everyone else indefinitely.
The cost of stronger guarantees is usually added complexity, more memory overhead, and harder proofs.
Why Developers Usually Start With Lock-Free
Lock-free algorithms are much more common in production because they often provide most of the performance benefit without the full cost of wait-freedom. For many systems, it is acceptable that a thread might retry under heavy contention as long as the whole structure keeps moving.
Wait-free design becomes more attractive when latency guarantees matter, such as hard real-time systems or code paths where starvation is unacceptable.
Memory Ordering Still Matters
Non-blocking does not mean "ignore the memory model." Atomic operations still need appropriate ordering semantics.
Without matching acquire and release semantics, one thread may observe stale data even if the synchronization variable changed.
Common Pitfalls
The most common mistake is calling an algorithm wait-free just because it uses atomics instead of a mutex. Atomics alone do not provide wait-freedom.
Another mistake is ignoring starvation. A compare-and-swap retry loop may look fast in testing but still allow a thread to lose indefinitely under contention.
Developers also underestimate memory reclamation. Lock-free linked structures often need hazard pointers, epoch-based reclamation, or another safe reclamation strategy before they are actually correct.
Finally, examples that are wait-free only because each thread owns separate memory do not automatically generalize to shared queues, stacks, or maps.
Summary
- Lock-free means system-wide progress; wait-free means per-thread progress.
- A compare-and-swap retry loop is usually lock-free, not wait-free.
- Wait-free algorithms are stronger but harder to design and prove.
- Real non-blocking structures still need correct memory ordering.
- Safe memory reclamation is part of correctness, not an optional extra.

