Monitors, Philosophers, and Deadlock introduction

advertisement
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
P1
•Philosophers alternate
between thinking and eating
P0
•2 chopsticks are required to
eat
Rice
P2
P4
•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
P3
•More than one philosopher
should be able to eat at a
time (no token ring!)
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.
1. Enumerate all of the resources, giving each a number.
2. 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
3. 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
•P1 grabs Chopstick1, blocking P0
P0
•P2 grabs Chopstick2, blocking P1
1
0
Rice
3
P4
•P3 grabs Chopstick3, blocking P2
2
4
P3
•P4 blocks trying to grab Chopstick0
P2
•P3 is free to grab Chopstick4
•P3 can eat!
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 >>>
}
Download