Monday, September 27, 1993 Today: semaphore example monitors ------------------------------------------------------------------------------- Example using semaphores: Dining philosophers N philosophers, each with a plate of spaghetti. Fork between each philosopher. Spaghetti requires two forks to eat (philosopher i needs fork i and i+1) Basic philosopher loop: Philosopher i: while(true) { think get_forks(i); eat release_forks(i); } Simple implementation : fork: array [0..N] of semaphore; get_forks(i) { P(fork[i]); P(fork[(i+1) mod N); } release_forks(i) { V(fork[i]); V(fork[(i+1) mod N]); } Deadlock possible (each philosopher gets one fork) Modification: pick up left fork, see if right fork is available. if not, release the left fork Starvation a possibility if in lock step (each picks up fork in unison, puts down fork, etc...) Goals for solution: no deadlock, no starvation, maximal concurrency (N-1 philosophers can eat at the same time) Approach: pick up forks only if both are available. Must be done in a critical section Add notion of philosopher's state, and add state of HUNGRY to existing states of THINKING and EATING semaphores: mutex (initially == 1) for fork acquisition and return phil(N), one per philosopher, to indicate that the philosopher is blocked awaiting fork release (initially == 0) get_forks(i) { P(mutex); state[i] = HUNGRY; test(i); /* to be defined---test that forks are available and acquire if so */ V(mutex); P(phil[i]); /* block if forks not available---see test() */ } put_forks(i) { P(mutex); state[i] = THINKING; test((i-1) mod N); test((i+1) mod N); V(mutex); } test(i) { if((state[i] == HUNGRY) && (state[(i-1) mod N] != EATING) && (state[(i+1) mod N] != EATING) && { state[i] = EATING; V(phil[i]); } } ------------------------------------------------------------------------------- Monitors High-level data abstraction tool based on abstract data types. For any distinct data type there should be a well-defined set of operations through which any instance of the data type *must* be manipulated. Monitor is implemented as collection of data (i.e., a resource) and a set of procedures that manipulate the resource. - access to resource possible only via one of monitor procedures - at any given time only one process may be executing inside the monitor (mutually exclusive). Other processes attempting to enter the monitor must delay. Higher level than P and V. Safer and easier to use. Details not sprinkled through the implementation. More structured interactions than permissible with P and V. syntax: type monitor-name = monitor variable declarations procedure entry P1 (...); begin ... end; procedure entry P2 (...); begin ... end; procedure L3 (...); begin .. end; begin initialization code end. Where P1 and P2 are entry points to the monitor. L3 is local code (not accessible outside of monitor's implementation). Condition variables let processes communicate by providing mechanism for process to "step out of monitor" and wait for some event to occur. var x: condition; x.wait; causes the process to release monitor lock and be suspended until some other process executes x.signal; x.signal resumes at most one suspended process. (Which one is resumed is characteristic of implementation; assume longest waiting one for simplicity). If no processes are waiting on the condition x, x.signal is a nop. ------------------------------------------------------------------------------- Bounded buffer with monitors: type buffer = monitor var Buf: array[0..n-1] of (buffer elements) nextin, nextout, full_cnt: integer; notempty, notfull: condition; procedure entry deposit(data: (buffer element data type)); begin if(full_cnt == n) then notfull.wait; Buf[nextin] = data; nextin = (nextin + 1) mod n; full_cnt = full_cnt + 1; notempty.signal; end; procedure entry remove(data: (data type)); begin if(full_cnt == 0) then notempty.wait; data = Buf[nextout]; nextout = (nextout + 1) mod n; full_cnt = full_cnt - 1; notfull.signal; end; begin /* initializations */ full_cnt = nextin = nextout = 0; end. ------------------------------------------------------------------------------- Next: communication with messages (interprocess communication)