190 likes | 319 Views
More Synchronisation. Last time: bounded buffer, readers-writers, dining philosophers Today: sleeping barber, monitors. What is the sleeping barber problem?. 1 barber N waiting chairs No customers -> barber sleeps Customer arrives -> wakes barber if asleep
E N D
159.335 More Synchronisation • Last time: • bounded buffer, readers-writers, dining philosophers • Today: • sleeping barber, monitors
159.335 What is the sleeping barber problem? • 1 barber • N waiting chairs • No customers -> barber sleeps • Customer arrives -> wakes barber if asleep • Otherwise if empty chair sit down, otherwise leave shop.
159.335 Barber Thread • Global Variables • Semaphore customers = 0; // no of waiting customers • Semaphore barbers = 0; // no of waiting barbers (0 or 1) • Semaphore mutex = 1; // protect critical sections • int waiting=0; • Barber • void barber() { • while(1) { • wait(customers); // wait for a customer • wait(mutex); // protect waiting • waiting--; • signal(barbers); // tell customer • signal(mutex); // release lock on waiting • cut_hair(); • } • }
159.335 Customer Thread • Customer • void customer() { • wait(mutex); // in CS • if(waiting < NO_CHAIRS) { // if no free chairs leave • waiting++; // one more waiting customer • signal(customers); // wakeup barber if necessary • signal(mutex); // release lock • wait(barbers); // wait until barber is free • get_haircut(); • } else { • signal(mutex); • } • }
159.335 Can Synchronisation be made easier? • What is a Monitor? • A High level synchronisation construct. i.e. Part of a programming language. • Why? • Semaphores are confusing because • 1. Two uses - mutex and ipc • 2. Can forget one of them or get in wrong order. • How? • Mutex: Put critical sections into separate functions and group together. This is called a monitor. • IPC: use special variables for wait and signal. These are called condition variables.
159.335 Monitor for Produce-Consumer • monitor ProducerConsumer { • condition full, empty; • int count=0; • void enter() { • if (count == N) wait(full); • ...enter item... • count++; • if (count == 1) signal(empty); • } • void remove() { • if (count == 0) wait(empty); • ...remove item... • count--; • if (count == N-1) signal(full); • } • }
159.335 Monitor for Produce-Consumer • void producer() { • while(1) { • ...produce item... • ProducerConsumer.enter(); • } • } • void consumer() { • while(1) { • ProducerConsumer.remove(); • ...consume item... • } • }
159.335 How are monitors implemented? • Using semaphores of course • What happens when a monitor signals a condition variable? A process waiting on the variable can't be active at the same time as the signalling process, therefore: 2 choices. • 1. Signalling process waits until the waiting process either leaves the monitor or waits for another condition. • 2. Waiting process waits until the signalling process either leaves the monitor or waits for another condition.
159.335 1st Choice signal(c) wait(c) signal(c) wait(c) wait(d)
159.335 Solution for 1st choice • Variables • semaphore mutex=1, next=0; • int next-count=0; • 'mutex' provides mutual exclusion inside the monitor. • 'next' is used to suspend signaling processes. • 'next-count' gives the number of processes suspended on 'next'.
159.335 Monitor Implementation • Each procedure F in the monitor is replaced by • wait(mutex); • ... • body of F; • ... • if (next-count > 0) • signal(next); • else signal(mutex);
159.335 Condition Variables • For each condition variable x, we have: • A Semaphore: • semaphore x-sem=0; • The number of threads waiting on x so we know if we have to wait after a signal. • int x-count=0;
159.335 Wait • The operation wait(x) can be implemented as: • x-count = x-count + 1; • if (next-count > 0) • signal(next); • else • signal(mutex); • wait(x-sem); • x-count = x-count - 1;
159.335 Signal • The operation signal(x) can be implemented as: • if (x-count > 0) { • next-count = next-count + 1; • signal(x-sem); • wait(next); • next-count = next-count - 1; • }
159.335 Dining Philosophers using monitors • monitor dining-philosophers { • status state[N]; • condition self[N]; • void pickup (int i) { • state[i] = hungry; • test (i); • if (state[i] != eating) • wait(self[i]); • } • void putdown (int i) { • state[i] = thinking; • test (i+N-1 % N); • test (i+1 % N); • } • void test (int k) { • if (state[k+N-1 % N]) != eating && state[k] == hungry • && state[k+1 % N] != eating) { • state[k] = eating; • signal(self[k]); • } • } • }
159.335 Dining Philosophers using monitors • void philosopher(int no) { • while (true) { • ...think.... • pickup(no); • ....eat..... • putdown(no) • } • } • Makes it easy to protect critical sections but you still need to identify the critical sections themselves (the hard part).
159.335 What languages have Monitors? • Ada and Java • How does Java do synchronisation? • use synchronized (with a z) in a member function definition • e.g. • public synchronized int get() {....} • There is one condition variable per class • use wait() and notify() • can use shared variables to simulate multiple condition variables.
159.335 Java Example class CubbyHole { private int seq; private boolean available = false; public synchronized int get() { while (available == false) wait(); available = false; notify(); return seq; } public synchronized void put(int value) { while (available == true) wait(); seq = value; available = true; notify(); } }
159.335 Fin