Operating Systems ECE344 Ashvin Goel ECE University of Toronto Classic Synchronization Problems
Classic Synchronization Examples Dining philosophers Readers and writers 2
The Dining Philosophers Problem Five philosophers sit at a table A fork lies between every pair of philosophers Philosophers (1) think, (2) grab one fork, (3) grab another fork, (4) eat, (5) put down one fork, (6) put the other fork 3
Dining Philosophers: Try 1 Assume take_fork and put_fork have locks in them to make them atomic o Is this solution correct? 4 #define N 5 Philosopher() { while(TRUE) { Think(); take_fork(i); take_fork((i+1)% N); Eat(); put_fork(i); put_fork((i+1)% N); } Each philosopher is modeled with a thread
Dining Philosophers: Try 2 5 #define N 5 Philosopher() { while(TRUE) { Think(); take_fork(i); take_fork((i+1)% N); Eat(); put_fork(i); put_fork((i+1)% N); } take_forks(i) put_forks(i)
Take Forks 6 // test whether philosopher i // can take both forks // only called with mutex set! test(int i) { if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING){ state[i] = EATING; // Signal Philosopher i V(sem[i]); } int state[N]; lock mutex; sem sem[N] = {0}; take_forks(int i) { lock(mutex); state[i] = HUNGRY; test(i); unlock(mutex); P(sem[i]); }
Put Forks 7 // test whether philosopher i // can take both forks // only called with mutex set! test(int i) { if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING){ state[i] = EATING; // Signal Philosopher i V(sem[i]); } put_forks(int i) { lock(mutex); state[i] = THINKING; test(LEFT); test(RIGHT); unlock(mutex); } int state[N]; lock mutex; sem sem[N] = {0};
The Readers and Writers Problem Multiple reader and writer threads want to access some shared data Multiple readers can read concurrently Writers must synchronize with readers and other writers Synchronization requirements o Only one writer can write the shared data at a time o When a writer is writing, no readers must access the data Goals o Maximize concurrency o Prevent starvation 8
Readers/Writers - Basics 9 Reader () { rc = rc + 1; // Read shared data rc = rc – 1; // non-critical section } Mutex lock = UNLOCKED; Semaphore data = 1; int rc = 0; Writer () { // non-critical section // Write shared data }
Readers/Writers - Mutex 10 Reader () { lock(lock); rc = rc + 1; unlock(lock); // Read shared data lock(lock); rc = rc – 1; unlock(lock); // non-critical section } Mutex lock = UNLOCKED; Semaphore data = 1; int rc = 0; Writer () { // non-critical section // Write shared data }
Readers/Writers – Synchronization Any problems with this solution? 11 Reader () { lock(lock); if (rc == 0) P(data); rc = rc + 1; unlock(lock); // Read shared data lock(lock); rc = rc – 1; if (rc == 0) V(data); unlock(lock); // non-critical section } Mutex lock = UNLOCKED; Semaphore data = 1; int rc = 0; Writer () { // non-critical section P(data); // Write shared data V(data); }