Chapter 7: Deadlocks: 7.5 Deadlock Avoidance
Chapter 7: Deadlocks: 7.5 Deadlock Avoidance
(From Operating System Concepts, 7th Edition, By: Silberschatz, Galvin & Gagne)
7.5 Deadlock Avoidance
Deadlock-prevention algorithms, as discussed in Section 7.4, prevent deadlocks by restraining how requests can be
made. The restraints ensure that at least one of the necessary conditions for deadlock cannot occur and, hence, that
deadlocks cannot hold. Possible side effects of preventing deadlocks by this method, however, are low device
utilization and reduced system throughput.
An alternative method for avoiding deadlocks is to require additional information about how resources are to be
requested. For example, in a system with one tape drive and one printer, the system might need to know that process
P will request first the tape drive and then the printer before releasing both resources, whereas process Q will request
first the printer and then the tape drive. With this knowledge of the complete sequence of requests and releases for
each process, the system can decide for each request whether or not the process should wait in order to avoid a
possible future deadlock. Each request requires that in making this decision the system consider the resources
currently available, the resources currently allocated to each process, and the future requests and releases of each
process.
The various algorithms that use this approach differ in the amount and type of information required. The simplest
and most useful model requires that each process declare the maximum number of resources of each type that it
may need. Given this a priori information, it is possible to construct an algorithm that ensures that the system will
never enter a deadlocked state. Such an algorithm defines the deadlock-avoidance approach. A deadlock-avoidance
algorithm dynamically examines the resource-allocation state to ensure that a circular-wait condition can never exist.
The resource-allocation state is defined by the number of available and allocated resources and the maximum
demands of the processes. In the following sections, we explore two deadlock-avoidance algorithms.
7.5.1 Safe State
A state is safe if the system can allocate resources to each process (up to its maximum) in some order and still avoid
a deadlock. More formally, a system is in a safe state only if there exists a safe sequence. A sequence of processes
is a safe sequence for the current allocation state if, for each , the resource requests that
can still make can be satisfied by the currently available resources plus the resources held by all , with . In
this situation, if the resources that needs are not immediately available, then can wait until all have finished.
When they have finished, can obtain all of its needed resources, complete its designated task, return its allocated
resources, and terminate. When terminates, can obtain its needed resources, and so on. If no such sequence
exists, then the system state is said to be unsafe.
A safe state is not a deadlocked state. Conversely, a deadlocked state is an unsafe state. Not all unsafe states are
deadlocks, however (Figure 7.5). An unsafe state may lead to a deadlock. As long as the state is safe, the operating
system can avoid unsafe (and deadlocked) states. In an unsafe state, the operating system cannot prevent processes
from requesting resources such that a deadlock occurs: The behavior of the processes controls unsafe states.
10 5
4 2
9 2
At time , the system is in a safe state. The sequence satisfies the safety condition. Process
can immediately be allocated all its tape drives and then return them (the system will then have 5 available tape
drives); then process can get all its tape drives and return them (the system will then have 10 available tape
drives); and finally process can get all its tape drives and return them (the system will then have all 12 tape drives
available).
A system can go from a safe state to an unsafe state. Suppose that, at time , process requests and is allocated
one more tape drive. The system is no longer in a safe state. At this point, only process can be allocated all its
tape drives. When it returns them, the system will have only 4 available tape drives. Since process is allocated 5
tape drives but has a maximum of 10, it may request 5 more tape drives. Since they are unavailable, process must
wait. Similarly, process may request an additional 6 tape drives and have to wait, resulting in a deadlock. Our
mistake was in granting the request from process for one more tape drive. If we had made wait until either of
the other processes had finished and released its resources, then we could have avoided the deadlock.
Given the concept of a safe state, we can define avoidance algorithms that ensure that the system will never
deadlock. The idea is simply to ensure that the system will always remain in a safe state. Initially, the system is in a
safe state. Whenever a process requests a resource that is currently available, the system must decide whether the
resource can be allocated immediately or whether the process must wait. The request is granted only if the allocation
leaves the system in a safe state.
In this scheme, if a process requests a resource that is currently available, it may still have to wait. Thus, resource
utilization may be lower than it would otherwise be.
To illustrate this algorithm, we consider the resource-allocation graph of Figure 7.6. Suppose that requests .
Although is currently free, we cannot allocate it to , since this action will create a cycle in the graph (Figure
7.7). A cycle indicates that the system is in an unsafe state. If requests , and requests , then a deadlock
will occur.
We can treat each row in the matrices Allocation and Need as vectors and refer to them as and .
The vector specifies the resources currently allocated to process ; the vector specifies the
additional resources that process may still request to complete its task.
7.5.3.1 Safety Algorithm
We can now present the algorithm for finding out whether or not a system is in a safe state. This algorithm can be
described as follows:
1. Let Work and Finish be vectors of length m and n , respectively. Initialize and
for , 1, …, .
2. Find an i such that both
a.
b.
.
4. If for all i , then the system is in a safe state.
This algorithm may require an order of operations to determine whether a state is safe.
7.5.3.2 Resource-Request Algorithm
We now describe the algorithm which determines if requests can be safely granted.
Let be the request vector for process . If , then process wants k instances of
resource type . When a request for resources is made by process , the following actions are taken:
1.
If , go to step 2. Otherwise, raise an error condition, since the process has exceeded its
maximum claim.
2.
If , go to step 3. Otherwise, must wait, since the resources are not available.
3. Have the system pretend to have allocated the requested resources to process by modifying the state as
follows:
If the resulting resource-allocation state is safe, the transaction is completed, and process is allocated its
resources. However, if the new state is unsafe, then must wait for , and the old resource-allocation
state is restored.
7.5.3.3 An Illustrative Example
Finally, to illustrate the use of the banker's algorithm, consider a system with five processes through and three
resource types A , B , and C . Resource type A has 10 instances, resource type B has 5 instances, and resource type
C has 7 instances. Suppose that, at time , the following snapshot of the system has been taken:
200 322
302 902
211 222
002 433
The content of the matrix Need is defined to be Max – Allocation and is as follows:
Need
ABC
743
122
600
011
431
We claim that the system is currently in a safe state. Indeed, the sequence satisfies the
safety criteria. Suppose now that process requests one additional instance of resource type A and two instances of
resource type C , so . To decide whether this request can be immediately granted, we first
check that —that is, that , which is true. We then pretend that this
request has been fulfilled, and we arrive at the following new state:
302 020
302 600
211 011
002 431
We must determine whether this new system state is safe. To do so, we execute our safety algorithm and find that
the sequence satisfies the safety requirement. Hence, we can immediately grant the
request of process .
You should be able to see, however, that when the system is in this state, a request for (3,3,0) by cannot be
granted, since the resources are not available. Furthermore, a request for (0,2,0) by cannot be granted, even
though the resources are available, since the resulting state is unsafe.
We leave it as a programming exercise to implement the banker's algorithm.
7.6 Deadlock Detection
If a system does not employ either a deadlock-prevention or a deadlock-avoidance algorithm, then a deadlock
situation may occur. In this environment, the system must provide:
An algorithm that examines the state of the system to determine whether a deadlock has occurred
In the following discussion, we elaborate on these two requirements as they pertain to systems with only a single
instance of each resource type, as well as to systems with several instances of each resource type. At this point,
however, we note that a detection-and-recovery scheme requires overhead that includes not only the run-time costs
of maintaining the necessary information and executing the detection algorithm but also the potential losses inherent
in recovering from a deadlock.
7.6.1 Single Instance of Each Resource Type
If all resources have only a single instance, then we can define a deadlock-detection algorithm that uses a variant of
the resource-allocation graph, called a wait-for graph. We obtain this graph from the resource-allocation graph by
removing the resource nodes and collapsing the appropriate edges.
More precisely, an edge from to in a wait-for graph implies that process is waiting for process to release
a resource that needs. An edge exists in a wait-for graph if and only if the corresponding resource-
allocation graph contains two edges and for some resource . For example, in Figure 7.8,
we present a resource-allocation graph and the corresponding wait-for graph.
Figure 7.8: (a) Resource-allocation graph. (b) Corresponding wait-for graph.
As before, a deadlock exists in the system if and only if the wait-for graph contains a cycle. To detect deadlocks, the
system needs to maintain the wait-for graph and periodically invoke an algorithm that searches for a cycle in the
graph. An algorithm to detect a cycle in a graph requires an order of operations, where n is the number of vertices
in the graph.
7.6.2 Several Instances of a Resource Type
The wait-for graph scheme is not applicable to a resource-allocation system with multiple instances of each resource
type. We turn now to a deadlock-detection algorithm that is applicable to such a system. The algorithm employs
several time-varying data structures that are similar to those used in the banker's algorithm (Section 7.5.3):
Available: A vector of length m indicates the number of available resources of each type.
Allocation: An matrix defines the number of resources of each type currently allocated to each process.
Request: An matrix indicates the current request of each process. If equals k , then
process is requesting k more instances of resource type .
The ≤ relation between two vectors is defined as in Section 7.5.3. To simplify notation, we again treat the rows in
the matrices Allocation and Request as vectors; we refer to them as and . The detection
algorithm described here simply investigates every possible allocation sequence for the processes that remain to be
completed. Compare this algorithm with the banker's algorithm of Section 7.5.3.
1. Let Work and Finish be vectors of length m and n , respectively. Initialize . For , 1, …,
, if , then otherwise, .
2. Find an index i such that both
a.
b.
This algorithm requires an order of operations to detect whether the system is in a deadlocked state.
You may wonder why we reclaim the resources of process (in step 3) as soon as we determine that
(in step 2b). We know that is currently not involved in a deadlock (since ).
Thus, we take an optimistic attitude and assume that will require no more resources to complete its task; it will
thus soon return all currently allocated resources to the system. If our assumption is incorrect, a deadlock may occur
later. That deadlock will be detected the next time the deadlock-detection algorithm is invoked.
To illustrate this algorithm, we consider a system with five processes through and three resource types A , B ,
and C . Resource type A has seven instances, resource type B has two instances, and resource type C has six
instances. Suppose that, at time , we have the following resource-allocation state:
200 202
303 000
211 100
002 002
We claim that the system is not in a deadlocked state. Indeed, if we execute our algorithm, we will find that the
sequence results in for all i .
Suppose now that process makes one additional request for an instance of type C . The Request matrix is
modified as follows:
Request
ABC
000
202
001
100
002
We claim that the system is now deadlocked. Although we can reclaim the resources held by process , the
number of available resources is not sufficient to fulfill the requests of the other processes. Thus, a deadlock exists,
consisting of processes , , , and .
7.6.3 Detection-Algorithm Usage
When should we invoke the detection algorithm? The answer depends on two factors:
1. How often is a deadlock likely to occur?
2. How many processes will be affected by deadlock when it happens?
If deadlocks occur frequently, then the detection algorithm should be invoked frequently. Resources allocated to
deadlocked processes will be idle until the deadlock can be broken. In addition, the number of processes involved in
the deadlock cycle may grow.
Deadlocks occur only when some process makes a request that cannot be granted immediately. This request may be
the final request that completes a chain of waiting processes. In the extreme, we can invoke the deadlock-detection
algorithm every time a request for allocation cannot be granted immediately. In this case, we can identify not only
the deadlocked set of processes but also the specific process that “caused” the deadlock. (In reality, each of the
deadlocked processes is a link in the cycle in the resource graph, so all of them, jointly, caused the deadlock.) If
there are many different resource types, one request may create many cycles in the resource graph, each cycle
completed by the most recent request and “caused” by the one identifiable process.
Of course, if the deadlock-detection algorithm is invoked for every resource request, this will incur a considerable
overhead in computation time. A less expensive alternative is simply to invoke the algorithm at less frequent
intervals—for example, once per hour or whenever CPU utilization drops below 40 percent. (A deadlock eventually
cripples system throughput and causes CPU utilization to drop.) If the detection algorithm is invoked at arbitrary
points in time, there may be many cycles in the resource graph. In this case, we would generally not be able to tell
which of the many deadlocked processes “caused” the deadlock.
7.7 Recovery from Deadlock
When a detection algorithm determines that a deadlock exists, several alternatives are available. One possibility is to
inform the operator that a deadlock has occurred and to let the operator deal with the deadlock manually. Another
possibility is to let the system recover from the deadlock automatically. There are two options for breaking a
deadlock. One is simply to abort one or more processes to break the circular wait. The other is to preempt some
resources from one or more of the deadlocked processes.
7.7.1 Process Termination
To eliminate deadlocks by aborting a process, we use one of two methods. In both methods, the system reclaims all
resources allocated to the terminated processes.
Abort all deadlocked processes: This method clearly will break the deadlock cycle, but at great expense; the
deadlocked processes may have computed for a long time, and the results of these partial computations must be
discarded and probably will have to be recomputed later.
Abort one process at a time until the deadlock cycle is eliminated: This method incurs considerable overhead,
since, after each process is aborted, a deadlock-detection algorithm must be invoked to determine whether any
processes are still deadlocked.
Aborting a process may not be easy. If the process was in the midst of updating a file, terminating it will leave that
file in an incorrect state. Similarly, if the process was in the midst of printing data on a printer, the system must reset
the printer to a correct state before printing the next job.
If the partial termination method is used, then we must determine which deadlocked process (or processes) should
be terminated. This determination is a policy decision, similar to CPU-scheduling decisions. The question is
basically an economic one; we should abort those processes whose termination will incur the minimum cost.
Unfortunately, the term minimum cost is not a precise one. Many factors may affect which process is chosen,
including:
1. What the priority of the process is
2. How long the process has computed and how much longer the process will compute before completing its
designated task
3. How many and what type of resources the process has used (for example, whether the resources are simple to
preempt)
4. How many more resources the process needs in order to complete
5. How many processes will need to be terminated
6. Whether the process is interactive or batch
7.7.2 Resource Preemption
To eliminate deadlocks using resource preemption, we successively preempt some resources from processes and
give these resources to other processes until the deadlock cycle is broken.
If preemption is required to deal with deadlocks, then three issues need to be addressed:
1. Selecting a victim. Which resources and which processes are to be preempted? As in process termination, we
must determine the order of preemption to minimize cost. Cost factors may include such parameters as the
number of resources a deadlocked process is holding and the amount of time the process has thus far consumed
during its execution.
2. Rollback. If we preempt a resource from a process, what should be done with that process? Clearly, it cannot
continue with its normal execution; it is missing some needed resource. We must roll back the process to some
safe state and restart it from that state.
Since, in general, it is difficult to determine what a safe state is, the simplest solution is a total rollback: Abort the
process and then restart it. Although it is more effective to roll back the process only as far as necessary to break
the deadlock, this method requires the system to keep more information about the state of all running processes.
3. Starvation. How do we ensure that starvation will not occur? That is, how can we guarantee that resources will
not always be preempted from the same process?
In a system where victim selection is based primarily on cost factors, it may happen that the same process is
always picked as a victim. As a result, this process never completes its designated task, a starvation situation that
must be dealt with in any practical system. Clearly, we must ensure that a process can be picked as a victim only
a (small) finite number of times. The most common solution is to include the number of rollbacks in the cost
factor.
Exercises
7.1 Consider the traffic deadlock depicted in Figure 7.9.
7.6 Consider a system consisting of four resources of the same type that are shared by three processes, each of which
needs at most two resources. Show that the system is deadlock free.
7.7 Consider a system consisting of m resources of the same type being shared by n processes. Resources can be
requested and released by processes only one at a time. Show that the system is deadlock free if the following
two conditions hold:
a. The maximum need of each process is between 1 and m resources.
b. The sum of all maximum needs is less than .
7.8 Consider the dining-philosophers problem where the chopsticks are placed at the center of the table and any two
of them could be used by a philosopher. Assume that requests for chopsticks are made one at a time. Describe a
simple rule for determining whether a particular request could be satisfied without causing deadlock given the
current allocation of chopsticks to philosophers.
7.9 Consider the same setting as the previous problem. Assume now that each philosopher requires three chopsticks
to eat and that resource requests are still issued separately. Describe some simple rules for determining whether a
particular request could be satisfied without causing deadlock given the current allocation of chopsticks to
philosophers.
7.10 We can obtain the banker's algorithm for a single resource type from the general banker's algorithm simply by
reducing the dimensionality of the various arrays by 1. Show through an example that the multiple resource-
type banker's scheme cannot be implemented by individual application of the single-resource-type scheme to
each resource type.
7.11 Consider the following snapshot of a system:
Allocation Max Available
0 01 2 0012 1520
1000 1750
1354 2356
0632 0652
0014 0656