Operating Systems ECE 344 Monitors Ashvin Goel ECE
- Slides: 10
Operating Systems ECE 344 Monitors Ashvin Goel ECE University of Toronto
Synchronization Methods q Monitors q Semaphores 2
Monitors: Mutual Exclusion q q Monitors provide systematic solution for both mutual exclusion and synchronization Mutual exclusion: Two requirements o Any shared data is accessed within methods of data structure Enqueue(queue) { lock(l); … unlock(l); } o Dequeue(queue) { lock(l); … unlock(l); } Methods acquire lock at the beginning, release lock at the end q Thus all shared data is accessed in critical section q Now programmer can focus on synchronization 3
Monitors: Synchronization q Synchronization Threads use one or more condition variables within methods o Condition variables allow a thread to 1) wait, or 2) wake up another waiting thread o q Condition variable abstraction o wait(cv, lock): § Wait on condition until Enqueue(queue) { lock(l); wait/signal; unlock(l); } another thread signals it § While thread waits, lock is released § When thread is signaled, it reacquires lock, returns o signal(cv, lock): § Wakeup one thread waiting on condition § If a signal occurs before a wait, signal does nothing 4
Variable Initialization Using Monitors char *V = NULL; lock l = FALSE; cv init_cv; // called by Thread T 1 // called by Thread T 2 Init() { Read() { lock(l); V = malloc(…); Sy // signal that V // wait until V is non-NULL n c wait(init_cv, l); // is non-NULL signal(init_cv, l); … assert(V); unlock(l); // read *V } … unlock(l); } q Is this code correct? o Signal can be lost 5
Variable Initialization Using Monitors char *V = NULL; lock l = FALSE; cv init_cv; // called by Thread T 1 Init() { lock(l); V = malloc(…); // signal that V // is non-NULL signal(init_cv, l); … unlock(l); } q Wait/signal within lock o // called by Thread T 2 Read() { lock(l); if (V == NULL) { CS // wait until V is non-NULL wait(init_cv, l); } assert(V); // read *V … unlock(l); } Would there be a problem if lock/unlock was not used above? 6
Producer-Consumer with Monitors Global variables: buf[n], in, out; lock l = FALSE; cv full; cv empty; Why use “while”, instead of “if”? void send(char elem) { lock(l); while ((in–out+n)%n == n - 1) { wait(full, l); } // full buf[in] = elem; in = (in + 1) % n; signal(empty, l); unlock(l); } q char receive() { lock(l); while (in == out) { wait(empty, l); } // empty elem = buf[out]; out = (out + 1) % n; signal(full, l); unlock(l); return elem; } This code works – no races, deadlocks, spinning! 7
Producer-Consumer: Try 6 Global variables: buf[n], in, out; lock l = FALSE; wait_queue full; wait_queue empty; void send(char elem) { lock(l); while ((in–out+n)%n == n - 1) { unlock(l); thread_sleep(full); wait lock(l); } // full buf[in] = elem; in = (in + 1) % n; thread_wakeup(empty); signal unlock(l); } char receive() { lock(l); while (in == out) { unlock(l); thread_sleep(empty); lock(l); } // empty elem = buf[out]; out = (out + 1) % n; thread_wakeup(full); unlock(l); return elem; } 8
Summary q Threads use synchronization to order their operations A thread waits on a condition; when another thread makes the condition occur, it wakes up waiting thread o Ad hoc solutions lead to races, deadlocks, spinning … o q Monitors provide a systematic method for synchronization All shared data is accessed within critical section o Synchronization is performed using condition variables o § Condition variables provide wait and signal operations q q Discussed solutions for variable initialization, producerconsumer problems using monitors Next lecture, semaphores 9
Think Time q q q Why are locks, by themselves, not sufficient for solving synchronization problems? Why is a lock passed to wait and signal in a monitor? What is the broadcast operation on a condition variable? 10