Theme
Q060. What is a Waker, and why does a future need one?
Short Answer
A Waker is a thread-safe handle that tells an executor a task may be able to make progress and should be polled again. When a future returns Pending, it registers or stores the current task's waker with the event source. The event source later calls wake or wake_by_ref. A wake-up schedules a poll; it does not complete the future, carry its output, or guarantee that the next poll returns Ready.
Deep Dive
Without wake-ups, an executor would need to repeatedly poll every pending future, wasting CPU, or risk never polling a future after its resource becomes ready.
The event source may be an I/O driver, timer, channel, or another future. It records a waker while the operation is not ready and triggers it when state changes. Implementations must avoid races between checking readiness and registering the waker, otherwise a notification can be lost.
A future should retain the current waker, not assume the first one is permanent. Wake-ups may be coalesced, and extra wake-ups are allowed. Correctness must come from checking the actual state again during poll.
Internal Model
Waker is built on a type-erased raw wake implementation and supports cloning, waking, and dropping. Executor-specific task metadata usually sits behind it. Calling wake places or marks the task in a ready queue.
Constructing a Waker manually through RawWaker is unsafe because its virtual table must uphold ownership and thread-safety contracts. Most application code uses wakers only through Context.
Example
rust
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::task::{Wake, Waker};
struct FlagWake(AtomicBool);
impl Wake for FlagWake {
fn wake(self: Arc<Self>) {
self.0.store(true, Ordering::Release);
}
}
fn main() {
let state = Arc::new(FlagWake(AtomicBool::new(false)));
let waker = Waker::from(Arc::clone(&state));
waker.wake_by_ref();
assert!(state.0.load(Ordering::Acquire));
}Common Mistakes
- Saying
wakeimmediately polls or completes the future. - Returning
Pendingwithout registering a waker. - Treating one stored waker as valid forever without checking for replacement.
Follow-ups
- How can a lost wake-up race occur?
- Why may executors coalesce several wake calls?
- What contracts make implementing
RawWakerunsafe?
Related
- Q059. How does
Future::pollwork? - Q061. What is the relationship between a future, a task, and an executor?
- Q072. How does the Tokio runtime schedule tasks?
References
- Rust Standard Library
- Async Book