Lock-Free Programming
debt(d9/e7/b7/t7)
Closest to 'silent in production until users hit it' (d9). Detection_hints explicitly states 'automated: no'. Lock-free bugs — ABA problems, subtle memory ordering violations, livelock — are notoriously invisible to compilers, linters, and most static analysis tools. They surface only under specific contention patterns in production, often appearing as rare data corruption or incorrect counters that only manifest at scale.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix advises using existing atomic primitives or well-tested abstractions rather than hand-rolled lock-free structures. But if hand-rolled lock-free code is already embedded, correcting it means identifying all affected data structures, understanding memory ordering semantics, handling the ABA problem, and replacing with safe primitives — a cross-cutting effort requiring deep expertise and touching multiple components wherever the flawed structure is used.
Closest to 'strong gravitational pull' (e7). Lock-free code applies across web, cli, and queue-worker contexts per applies_to. Once hand-rolled lock-free structures are introduced, every future maintainer must deeply understand CAS semantics, memory ordering, and the ABA problem. The choice shapes every concurrent access path and makes the code resistant to modification — any future change risks introducing races, bending all nearby development around the constraint.
Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The canonical misconception is explicit: 'Lock-free code is always faster than locking — under low contention, mutexes can be faster (no retry loops).' Developers with locking experience expect lock-free to be a strict upgrade, but it can be slower under low contention due to retry loops, and introduces entirely new failure modes (ABA problem) that have no analogue in mutex-based code. The 'obvious' optimization path leads to both worse performance and harder-to-find bugs.
TL;DR
Explanation
Lock-free vs wait-free: lock-free guarantees system-wide progress (at least one thread advances); wait-free guarantees per-thread progress (every thread advances in bounded steps). Lock-free data structures: queues, stacks, counters using CAS. Benefits: no deadlocks, no priority inversion, better cache performance (no lock contention). Downsides: extremely hard to implement correctly (ABA problem, memory ordering, spurious failures). In practice: use well-tested atomic libraries, not hand-rolled lock-free structures. PHP: Redis atomic commands are effectively lock-free for simple operations.
Common Misconception
Why It Matters
Common Mistakes
- Hand-rolling lock-free structures without deep expertise — subtle bugs.
- Ignoring the ABA problem — a value returning to A after changing to B fools CAS.
- Using lock-free for high-level application logic — overkill; use well-tested primitives.
Code Examples
// Naive lock-free counter — broken ABA problem in complex scenarios:
$expected = $counter->get();
$counter->cas($expected, $expected + 1); // May fail spuriously under ABA
// Use Redis INCR (lock-free counter, proven implementation):
$count = $redis->incr('visitors');
// Or DB atomic:
DB::statement('UPDATE stats SET count = count + 1 WHERE id = 1');