279. thread::park — Block a Thread Without Dragging In a Mutex
This morning’s bite (278) needed a Mutex + Condvar pair just to make one thread wait for another. When exactly one thread sleeps and you hold its handle, thread::park does it with no lock at all.
Every thread owns a park token. thread::park() blocks until the token is available, then consumes it; unpark() makes it available. That token is the whole trick:
| |
With a naive flag-and-sleep scheme, waking a thread before it goes to sleep means the wakeup is lost. The token can’t be lost: an early unpark is banked, and the next park returns immediately. That’s the race Condvar needs its Mutex to prevent — park solves it for free.
One Condvar lesson still applies, though: park may also wake spuriously, so pair it with a flag and re-check in a loop:
| |
The flag decides whether to run; park only decides when to stop burning CPU. Store with Release, load with Acquire, and the write is visible when the loop exits — the exact handoff from bite 277.
Note what you didn’t need: no Mutex, no guard rebinding, no Condvar. The waiter is addressed directly through its Thread handle (worker.thread() — cloneable, Send, happy to be stashed anywhere).
There’s a deadline-aware sibling, thread::park_timeout(dur), for “wake me up when signaled, or after 10ms, whichever comes first” — the classic backoff loop in lock-free code.
Reach for Condvar when many threads wait on shared state; reach for park when one known thread naps until another taps it. It’s what mpsc channels and most executors use under the hood.
Stable since Rust 1.0.