Monitors
A language-level construct: a mutex plus condition variables bundled with the data.
Level: intermediate
What is it?
A monitor is a concurrency abstraction that encapsulates shared state, operations on that state, and synchronization. In common designs, only one thread executes a monitor procedure at a time, and condition variables let threads wait until a state predicate may become true.
Why does it matter?
Encapsulation keeps the locking discipline close to the data invariant. This reduces the chance that a caller forgets to acquire a lock or changes state through an unsafe access path.
Mental model
Think of the monitor as a guarded room containing both the resource and its rules. Callers request operations rather than manipulating the shared state directly; condition variables provide a queue for threads waiting for a particular condition.
How it works
- Monitor procedures protect the shared invariant according to the monitor's mutual-exclusion rules.
- Condition variables represent waiting for a predicate, not a durable count of events.
- A wait generally releases the monitor lock while sleeping and reacquires it before returning.
- Because another thread may change the state before a woken thread proceeds, predicate checks belong in a loop.
- Monitor semantics vary by language and runtime, so confirm whether signaling hands off immediately or merely makes a waiter runnable.
Steps
- A bounded queue stores a mutex-protected queue and a notEmpty condition variable.
- A consumer acquires the monitor and loops while the queue is empty, waiting on notEmpty.
- A producer adds an item while holding the monitor and signals notEmpty.
- The consumer wakes, reacquires the monitor, rechecks the predicate, and removes the item.
Real-world usage
- Designing thread-safe classes with a clear state boundary.
- Implementing queues, caches, and resource managers.
- Choosing between monitor-style abstractions and lower-level semaphore protocols.
Common mistakes
- Exposing mutable monitor state outside the synchronization boundary.
- Using a single if before a condition wait rather than rechecking the predicate.
- Assuming every language implements condition-variable signaling with identical scheduling semantics.
Interview questions
How does a monitor differ from a bare mutex?
A monitor packages shared state and operations with synchronization, while a mutex is a lower-level primitive that callers must apply consistently.
Why should code recheck a condition after a monitor wait?
The state may have changed before the thread reacquires the lock, or the wait may return spuriously; the predicate must still be true.