The race
A lost wakeup happens when a notification is sent before a thread starts waiting, so the waiter sleeps forever having missed the only signal it would ever get. The condition it cares about already became true, but it checks too late and then blocks.
The classic mistake
The bug appears when code checks a condition and waits without holding the right lock across both steps:
- Thread A sees the queue is empty and decides to wait.
- Thread B adds an item and signals the condition.
- Thread A now calls wait, after the signal already passed.
The correct pattern
Condition variables must be used with a held lock and a predicate loop:
- Acquire the mutex.
- Loop while the condition is false, calling wait, which atomically releases the mutex and sleeps.
- Re check the predicate on every wakeup to also handle spurious wakeups.
Key idea
A wakeup is lost when you signal before the waiter sleeps. Hold the lock and wait inside a while predicate loop so the check and the sleep cannot be split.