120 likes | 264 Views
Review: Monitor Semantics. If P does X.wait() and later Q does X.signal(): Hoare Semantics: Q blocks yielding the monitor immediately to P Mesa Semantics: Q continues. P becomes runnable. P will eventually run, but only after Q exits Brinch Hanson:
E N D
Review: Monitor Semantics • If P does X.wait() and later Q does X.signal(): • Hoare Semantics: • Q blocks yielding the monitor immediately to P • Mesa Semantics: • Q continues. P becomes runnable. P will eventually run, but only after Q exits • Brinch Hanson: • Q can only signal as it exits, so P will run next. • Java synchrnoized methodsj: • Only one reason to wait can exist. Notify() (the Java equivalent of signal() ) makes the blocked thread runnable as with Mesa semantics – it will run at a later time, after Q exits the monitor.
Mesa vs. Hoare • MONITOR prod-con { • struct something buffer[n]; • int in=0, out=0; • int count=0; • condition=full, empty; • entry void add_item(data) { • /* Mesa semantics require a while – why? Bounded wait? */ • if/while (count==n) full.wait(); • buffer[in] = data; • in = (in + 1) % n; • count++; • empty.signal(); • } • /* continued */
Mesa vs. Hoare (cont.) • /* continued */ • entry remove_item (data_ptr) • { • /* Mesa semantics require a while – why? Bounded wait? */ • if/while (count == n) empty.wait(); • *data_ptr = buffer[out]; • out = (out + 1) % n; • count--; • full.signal(); • }
Dining philosophers • Rules • Philosophers alternate between thinking and eating • 2 chopsticks are required to eat • Philosophers never grab with both hands – they reach for one chopstick at a time. • A philosopher is too polite to steal a chopstick from a colleague • The philosophers cannot be allowed to starve • More than one philosopher should be able to eat at a time (no token ring!) P1 P0 Rice P2 P4 P3
Dining Philosophers: Approach 1 • #define left(i) (i) • #define right(i) ((i-1) % 5) • MONITOR fork { • int avail[5] = {2, 2, 2, 2, 2 }; /* forks available to each phil */ • condition hungry[5]; • entry pickup_fork (int phil) { • if (avail[i] != 2) ready[i].wait(); • avail[left(I)]--; avail[right(I)]--; • } • entry putdown_fork (int phil) { • avail[left(i)]++: avail[right(i)]++; • if (avail[left(i)] == 2) ready[left(i).signal(); • if (avail[right(i)] == 2) ready[right(i)].signal(); • } • }
Why Starvation? • Each philosopher is waiting for a different condition, so we can’t ensure fairness. • The solution is simple: all philosophers should wait for the same condition, such as their turn in a common queue.
Dining Philosophers: Approach 2 • Semaphore chopstick[5] = { 1, 1, 1, 1, 1 }; • while (1) • { • P(chopstick[i]); • P(chopstick[(i+1) % 5]); • <<< eat >>> • V(chopstick[i]); • V(chopstick[(i +1) % 5]); • <<< think >>> • }
What is Deadlock? • First, let’s define a resource: • Resources are an abstraction of any reason to wait. • Resources come in different types and we can have different numbers of each type. • A process/thread can acquire a resource, use it, and then fee it. • In this context, resources are unshareable – they are serially reusable. • Now let’s formally define deadlock: • The condition that arises when there exists a set of processes (or threads) such that each process holds a resource that another process in the set is waiting to acquire. The situation forces all processes in the set to wait forever.
Why Deadlock? • Deadlock can occur if these conditions are satisfied: • Mutual exclusion – at least one resource must be held by a process. • Hold and wait – at least one process hold a resource while it is waiting for another resource. • No preemption – one process can’t take another process’s resources in order to make progress (nor can the OS) • Circular wait – there exists a circular chain of processes, each of which is waiting for a resource held by the next process in the chain.
Simple Defense: Serialization • One simple defense against deadlock is to serialize the request of resources. • Enumerate all of the resources, giving each a number. • Require that all processes request resources in the order of this enumeration. That is to say that they are designed so that they never request a resource with a lower number than the highest numbered resource that they hold • Circular wait is now impossible, because the chain of waiting cannot wrap around from the greatest back to the beginning. It will eventually unfold.
Dining philosophers - Serialized • Trace • P0 grabs Chopstick0, blocking P4 • P1 grabs Chopstick1, blocking P0 • P2 grabs Chopstick2, blocking P1 • P3 grabs Chopstick3, blocking P2 • P4 blocks trying to grab Chopstick0 • P3 is free to grab Chopstick4 • P3 can eat! P1 P0 1 2 Rice 0 P2 3 P4 4 P3
Dining Philosophers: Approach 3 • Semaphore chopstick[5] = { 1, 1, 1, 1, 1 }; • while (1) • { • if (i < ((i+1) % 5)) { • P(chopstick[i]); • P(chopstick[(i+1) % 5]); • } else { • P(chopstick[(i+1) % 5]); • P (chopstick[i]); • } • <<< eat >>> • V(chopstick[i]); • V(chopstick[(i +1) % 5]); • <<< think >>> • }