Operating Systems: Three Easy Pieces Ch. 30
Condition Variables
- Checking whether a condition is true before continuing its execution
- If the parent thread might wish to check whether a child thread has been completed before continuing
- Waiting for a condition to become true → condition variable
- Explicit queue that threads can put themselves on when some state of execution is not as desired
- When the state has been changed, then wake one of those on the waiting queue
- Wait
- release the lock and put the calling thread to sleep
- Wakes up, re-acquire the lock before returning to the caller
- The parent continues running itself and thus immediately calls into thr_join()
- Need to check the child is done and put itself to sleep by calling wait
- The child runs immediately upon creating, sets done to 1, calls a signal to wake a sleeping thread, and is done. The parent then runs, calls thr_join(), done is 1 already, so does not wait for anything
- No state variable
- State variable done → records the value the threads are interested in knowing
- If there is no thread asleep on the condition → if parent calls wait and no thread can be woke up
- Race condition
- No lock
- Parent check the value of done and set to 0 → Before it calls wait to go to sleep, interrupt
- Child runs → child change the state variable as 1 and interrupt(signal)
- no thread is waiting, parent is sleeping forever
- Producer/Consumer
- Bounded - buffer
- Shared resources require synchronized access
- Producer thread
- Consumer thread
- On the multiple threads
- The state of the bounded buffer changed because of different buffer
- Mesa semantics
- no guarantee that when the woken thread runs, the state will still be as desired
- first research that built a condition variable in such a manner
- Hoare semantics
- harder to build but provides a stronger guarantee that the woken thread will run immediately upon being woken
- Bounded - buffer
- While
- Always use while loops
- When two consumer run first
- Both realize the buffer is empty → sleep
- Produce fill the buffer and wakes the one of consumer
- Consumer wakes, rechecks the condition, the buffer is full, consumes, then need to wake the producer → how?
- Signaling is clearly needed
- Clear signal
- use two condition variables, instead of one, in order to properly signal which type of thread should wake up when the state of the system changes
- Example
- Empty condition
- Full condition
- Producer wait on the condition empty, signal fills
- Consumer wait on fil and signal empty
- More buffer slots
- Multiple value can be produced, consumed before sleeping
- Using put and get
- A producer only sleeps if all buffers are currently filled
- A consumer only sleeps if all buffers are currently empty
- Covering Conditions
- Wake all waiting threads
- threads will simply wake up, re-check the condition, and then go immediately back to sleep
- it covers all the cases where a thread needs to wake up
- It might be better for certain case
- Wake all waiting threads