Chapter 6
Deadlock
A set T of threads is said to be deadlocked if each thread in T cannot
proceed until an action is performed by some other thread in T.
Deadlock can occur any time threads acquire multiple resources, perform work,
and then release their resources.
Example.
Two processes A and B, with two semaphores a and b, both of which are initialized to 1.
A: B:
P(a); P(b);
P(b); P(a);
V(b); V(a);
V(a); V(b);
Necessary Conditions for deadlock:
- mutual exclusion -- the resource may be used by only one thread at a time.
- no preemption -- threads can only release a resource voluntarily. Another thread (even the OS) cannot force the thread to release the resource.
- "hold and wait" - more properly called multiple independent requests -- a thread holds a resource and is waiting for other resources to become available.
- circular chain of requests -- A set of waiting threads t_1, t_2, ..., t_n, where each t_i is waiting for t_i+1 and T_n is waiting for t_1.
Solutions to the deadlock problem fall into three general categories:
Deadlock avoidance algorithms check resource requests and availability to avoid deadlock.
Deadlock prevention algorithms make deadlock logically impossible. May lead to inefficient use of resources.
Deadlock detection algorithms look for instances of deadlock when processes stop making progress. If a deadlock is found, one or more processes must be killed. This method is usually not practical, but may be the only solution available in a distributed system.
Example: Deadlock Avoidance
The Banker's Algorithm
Example: Deadlock Prevention
Ordering resources
>hr>
Deadlock avoidance and prevention must eliminate one of the four necessary conditions for deadlock.
- Don't allow exclusive access. This is probably not reasonable
for many applications.
-
Create enough resources so that there's always plenty for all.
-
Don't allow waiting. The phone company solution.
This punts the problem back to the user.
-
Allow preemption.
Is this ever feasible?
-
Make process ask for everything at once. Either get them all
or wait for them all. Tricky to implement: a process must be able to wait
on many things without locking anything. Painful for process:
may be difficult to predict, so must make very wasteful use of
resources. This requires the process to predict the future.
-
Make ordered or hierarchical requests. E.g. ask for
all S's, then all T's, etc. All processes must follow the same
ordering scheme. Of course, for this you have to know in advance
what is needed.