Monitors
Monitors Basics
- locks: mutual exclusion, synchronize threads so they don't access shared data at the same time
- sometimes we need more than just data synchronization
- parent need to sleep until child exits
- lock waiters sleeps until the lock is free
- event based synchronization requires additional mechanism
- monitors
- synchronization construct that allows threads to block/unblock on events/conditions
- conditions are accessible and updated by multiple threads
- a lock is needed to protect access to the condition(s)
- block/unblock requires us to keep track of waiters on the condition
- condition variables!
- a primitive that tracks a list of waiters and have APIs for blocking & unblocking
- a monitor = a lock + any number of condition & condition variable
- lock: protects access to the condition(s) and condition variable(s)
- condition: the event(s) we are synchronizing on
- for wait: child's proc_state == ZOMBIE
- for lock_acquire: lock's state == free
- to produce water: hydrogen atom >= 2 && oxygen atom >= 1
- condition variable: mechanism to manage waiters of a condition
- tracks a list of waiters for a condition
- adds a thread to list when condition is not true and blocks the thread
- removes a thread from list when condition might be true and unblocks the thread
Condition Variable APIs
- access to condition variables should always be done while holding the lock! why?
cv_wait
- puts the calling thread on the waiter list, atomically blocks the thread and releases the monitor lock
- how to block a thread? must invoke the scheduler
- why release the monitor lock? will the condition ever change if we don't release the lock?
- why do these steps need to happen atomically?
- what happens to the monitor lock when wait returns?
cv_signal
- removes a waiter from the waiter list, wakes up/unblocks the waiter
- how to unblock a thread? must coordinate with the scheduler to change proc's state to READY
- where does the waiter resume upon a wakeup?
cv_broadcast
- removes all waiters from the waiter list, wake uup all
- why would we want to do this?
- how are these APIs used?
Monitor Design Pattern
- always grab the lock before accessing condition and condition variable
- always release the lock after accessing condition and condition variable
cv_wait
when condition is not met, always cv_wait
in a while loop
- Mesa vs Hoare semantics
- spurious wakeup: condition might still not be true when the waiter wakes up
- examples