Chapter 7 PowerPoint

advertisement
Operating System Concepts
chapter 7
CS 355
Operating Systems
Dr. Matthew Wright
Deadlock Problem
• Deadlock: A set of processes, each holding a resource,
and each waiting to acquire a resource held by another
process in the set.
• Example:
–Suppose a system has two disk drives.
–Processes P1 and P2 each hold one disk drive and are
waiting for the other drive.
• Multithreaded processes are good candidates for
deadlock because multiple threads can be competing for
shared resources.
Deadlock Characterization
Deadlock requires that four conditions hold simultaneously:
1. Mutual exclusion: only one process can use a resource at a
time
2. Hold and wait: a process holding a resource is waiting to
acquire a resource held by other processes
3. No preemption: a resource can only be released voluntarily
by the process holding it, after it has completed its task
4. Circular wait: there exists a set {P0, P1, ..., Pn} of waiting
processes such that P0 is waiting for a resource held by P1, P1
is waiting for a resource held by P2, ..., Pn-1 is waiting for a
resource held by Pn, and Pn is waiting for a resource held by
P0.
Resource-Allocation Graph
• Round nodes indicate processes.
• Rectangular nodes indicate resources,
which might have multiple instances.
• An arrow from a process to a
resource indicates that the process
has requested the resource.
• An arrow from a resource to a
process indicates that the resource
has been allocated to the process.
• If the graph contains no cycles, then
there is no deadlock.
• If each resource has only one
instance, then a cycle indicates
deadlock.
R1
P1
R3
P2
P3
no deadlock
deadlock
R2
R4
Resource-Allocation Graph
• Note: A cycle indicates the possibility of deadlock. It does not
guarantee that a deadlock exists.
• Example: The following resource-allocation graph contains a cycle,
but not a deadlock:
P2
R1
P1
P3
R2
P4
Java Deadlock Example
The following program might or might not cause deadlock when it is run.
class A implements Runnable
{
private Lock one, two;
public A(Lock one, Lock two) {
this.one = one;
this.two = two;
}
class B implements Runnable
{
private Lock one, two;
public A(Lock one, Lock two) {
this.one = one;
this.two = two;
}
public void run() {
public void run() {
public
class
DeadlockExample
try {
try {
{
one.lock();
two.lock();
public
static
void
main
arg[]) {
// do something
// do(String
something
Lock lockX = new ReentrantLock();
two.lock();
one.lock();
Lock
lockY
=
new
ReentrantLock();
// do something else
// do something else
}
}
Thread
threadA
=
new Thread(new
A(lockX, lockY));
finally {
finally
{
Thread threadB = new
Thread(new B(lockX, lockY));
one.unlock();
two.unlock();
two.unlock();
one.unlock();
threadA.start();
}
}
threadB.start();
}
}
}
}
}
}
Handling Deadlocks
Three strategies for handling deadlocks:
1. Ensure that the system will never enter a deadlocked
state.
2. Allow the system to enter a deadlocked state, detect it,
and recover.
3. Ignore the problem and pretend that deadlocks never
occur.
Strategy 3 is employed by
most operating systems,
including UNIX, Windows,
and the JVM.
Deadlock Prevention
Deadlock prevention: ensure that at least one of the four necessary
conditions for deadlock cannot hold
1. Mutual exclusion: Can we eliminate mutual exclusion?
• Sharable resources (e.g. read-only files) cannot be involved in
deadlock.
• Since some resources are intrinsically nonsharable, we generally
cannot remove the mutual exclusion condition.
2. Hold and wait: How could we guarantee that a process never holds a
resource while it waits for another?
• We could require that a process holding any resource may not request
another resource (e.g. a process must request all resources when it is
created).
• We could require that a process releases all resources before making a
request for another resource.
• These protocols are not efficient.
Deadlock Prevention
3. No preemption: We could preempt resources from processes.
• If a process requests resources that are not available, we could
preempt any resources that it currently holds.
• If a process requests resources held by another waiting process, we
could preempt them from the other process.
• Preemption is difficult if the state of a resource cannot easily be saved
and restored.
4. Circular wait: Can we eliminate circular waits?
• We could require that processes request resources in a particular
order (e.g. tape drives, then disk drives, and finally printers).
• An ordering could be implemented in Java by using
System.identityHashCode().
• Often, requiring resource requests in a particular order is not
convenient.
Deadlock Avoidance
• OS requires additional information from each process about the
resources it will need, and the OS makes processes wait if they make a
request that would produce deadlock.
• Simple strategy:
– Require each profess to declare in advance the maximum number of
resources of each type that it will need.
– The system then allocates resources in such a way that a circular wait
condition never exists.
• Safe state: The system is safe if it can allocate resources to each process
and avoid deadlock.
• Safe sequence: A sequence of processes (P1, P2, ..., Pn) is safe if the
resources required by Pi can be satisfied by the currently available
resources plus those held by all Pj, with j < i.
Deadlock Avoidance
• Safe state: The system is safe if it
can allocate resources to each
process and avoid deadlock.
• Unsafe state: The system might
not be able to allocate resources
to each processes and avoid
deadlock.
• An unsafe state is not necessarily
deadlocked!
Deadlock Avoidance Example
Suppose a system has 10 tape drives and 3 processes:
Maximum Needs
Allocation at t0
P0
8
3
P1
6
4
P2
3
2
At t0, the system is safe. Processes can run in the order P2, P1, P0.
However, suppose that we let process P1 run and it requests and is
allocated another tape drive at time t1. The system state is then:
Maximum Needs
Allocation at t1
P0
8
3
P1
6
5
P2
3
2
This state is unsafe, because any process that runs next might request
another tape drive, which we would be unable to allocate.
Deadlock Avoidance Strategy
• When a process requests resources, grant the resources
only if the system will still be in a safe state.
• Resource utilization may be lower than it would
otherwise be.
• If there is only one instance of each resource, we can
implement this strategy using a variant of the resourceallocation graph.
• If there are multiple instances of each resource, we can
use the “Banker’s Algorithm.”
Resource-Allocation-Graph Algorithm
• This avoids deadlock if there is only one instance of each resource type.
• Initially, each process must specify which resources it might request in
the future.
• In the resource allocation graph, a dotted arrow from Pi to Rj is a claim
edge, indicating that Pi might request Rj in the future.
• If the request occurs, the claim edge is converted to a request edge.
• A request can be granted if and only if converting the request edge to an
assignment edge does not result in a cycle in the graph.
• Cycle-detection algorithms are O(n2), where n is the number of vertices.
R1
P1
R1
P2
P1
P2
R2
R2
Safe: no cycle
Unsafe: a cycle
Banker’s Algorithm
• This avoids deadlock if there are many instances of each resource type.
• We must maintain the following data structures:
(n is number of processes and m is number of resource types)
– Available: vector of length m, indicating the number of available resources of
each type
Available[j] is the number of instances of resource Rj.
– Max: n x m matrix, indicating the maximum demand of each process
Max[i][j] is the maximum number of instances of resource Rj that process Pi
may request.
– Allocation: n x m matrix, indicating the resources of each type currently
allocated to each process
Allocation[i][j] is the number of instances of resource Rj currently allocated
to process Pi.
– Need: n x m matrix, indicating the remaining resource need of each process
Need[i][j] = Max[i][j] – Allocation[i][j]
Banker’s Algorithm
Safety Algorithm: determines whether or not the system is in a safe state;
the algorithm is O(mn2)
1. Let Work be a vector of length m,
and set Work = Available. Let Finish
be a vector of length n, initialized
so that each entry is false.
2. Find an index i such that both
a. Finish[i] == false
b. Need[i] ≤ Work
If no such i exists, go to step 4.
3. Work = Work + Allocation[i]
Finish[i] = true
Go to step 2.
4. If Finish[i] == true for all i, then the
system is safe. Otherwise, the
system is unsafe.
Example
3 resources: A (has 6 instances), B (has
3 instances), and C (has 4 instances)
4 processes, P0, P1, P2, P3, with
maximums and allocations:
P0
P1
P2
P3
A
2
4
5
3
Max
B
2
0
2
2
C
1
2
2
0
Allocation
A B C
1 1 1
1 0 2
0 0 0
1 2 0
Is the system in a safe state?
Banker’s Algorithm
Resource-Request Algorithm: determines whether resources can be safely granted
Let Request[i] be the request vector
for Pi.
1. If Request[i] ≤ Need[i], go to step 2.
Otherwise, the request exceeds the
process’ maximum.
2. If Request[i] ≤ Available[i], go to
step 3. Otherwise, Pi must wait.
3. Pretend to grant the request, as
follows:
Available = Available – Request[i]
Allocation[i] = Allocation[i] + Request[i]
Need[i] = Need[i] – Request[i]
Check to see if the system would
still be safe, then grant the request.
Otherwise, roll back the changes
and make Pi wait.
Example
3 resources: A (has 6 instances), B (has
3 instances), and C (has 4 instances)
4 processes, as before:
P0
P1
P2
P3
A
2
4
5
3
Max
B
2
0
2
2
C
1
2
2
0
Allocation
A B C
1 1 1
1 0 2
0 0 0
1 2 0
What happens if the following requests
are made (starting from the above
state each time)?
a. P0 requests [1, 0, 0]
b. P2 requests [4, 0, 1]
c. P2 requests [2, 0, 1]
Deadlock Detection
• If a system does not prevent deadlocks, it may provide:
– An algorithm that examines the state of the system to determine
whether a deadlock has occurred
– An algorithm to recover from deadlock
• If all resources have only a single instance, detecting deadlock involves
looking for a cycle in the resource-allocation graph.
• In fact, we can collapse the resource-allocation graph to a wait-for graph,
which indicates which processes are waiting for which other processes to
release resources.
P5
R1
resourceallocation
graph
R3
P5
R4
P1
P1
R2
P2
P4
P2
P3
P4
corresponding
wait-for graph
P3
R5
Deadlock Detection Algorithm
• If some resources have multiple instances, we must use the
following data structures, similar to those in the Banker’s
Algorithm:
– Available: vector of length m, indicating the number of available
resources of each type
Available[j] is the number of instances of resource Rj.
– Allocation: n x m matrix, indicating the resources of each type
currently allocated to each process
Allocation[i][j] is the number of instances of resource Rj currently
allocated to process Pi.
– Request: n x m matrix, indicating the current request of each process
Request[i][j] is the number of instances of resource Rj requested by
Pi.
• The deadlock detection algorithm is O(mn2).
Deadlock Detection Algorithm
1. Let Work be a vector of length m,
and set Work = Available.
Let Finish be a vector of length n. If
Allocation[i] = 0, set Finish[i] = true;
otherwise, set Finish[i] = false.
2. Find an index i such that both
a. Finish[i] == false
b. Request[i] ≤ Work
If no such i exists, go to step 4.
3. Work = Work + Allocation[i]
Finish[i] = true
Go to step 2.
4. If Finish[i] == false for some i, then
the system is in a deadlocked state.
Example
3 resources: A (has 7 instances), B (has
4 instances), and C (has 2 instances)
4 processes, as before:
P0
P1
P2
P3
Allocation
A B C
2 1 1
1 0 0
0 0 0
1 1 0
Request
A B C
1 2 1
6 0 2
5 4 1
3 2 2
Is the system deadlocked?
What if P1 instead requests [4, 2, 1]?
Deadlock Algorithm Usage
• How often should we run the deadlock detection algorithm?
• Factors to consider:
– How often is deadlock likely to occur?
– How many processes will be affected by deadlock if it
happens?
• Running the deadlock detection algorithm whenever a
process requests a resource would be computationally
expensive.
• We could run the algorithm at periodic intervals (e.g. every
hour).
• We could run the algorithm when CPU utilization drops
below some threshold (e.g. 40%).
Deadlock Recovery
• One way to recover from deadlock is to terminate processes.
• Two strategies:
1. Abort all deadlocked processes: will surely work, but very expensive
2. Abort processes individually until deadlock is eliminated: still
expensive, since we have to run the deadlock detection algorithm
after each process terminated
• Aborting processes is tricky, because the system could be left in an
inconsistent state (e.g. if the process was in the midst of updating a file).
• How do we choose which processes to terminate? Consider:
– What is the priority of the process?
– Are the resources held by the process are easy to preempt?
– What is the least number or processes whose termination would
resolve the deadlock?
– How much computation would be repeated if the processes is
restarted?
Deadlock Recovery
• Another way to recover from deadlock is to preempt resources.
• Three issues:
1. Selecting a victim: Which resources should be preempted from
which processes? How expensive will this be?
2. Rollback: If we preempt a resource from a process, what
happens to that process? Can we roll the process back to a
previous state? Perhaps we will need to abort the process.
3. Starvation: How do we ensure that starvation will not occur?
(i.e. we shouldn’t always preempt resources from the same
process)
Download