0% found this document useful (0 votes)
82 views12 pages

Chapter 7: Deadlocks: 7.5 Deadlock Avoidance

This document summarizes deadlock avoidance techniques, specifically the safe state approach and two algorithms: the resource-allocation-graph algorithm and Banker's algorithm. The safe state approach ensures that the system is always in a safe state where resources can be allocated without leading to a deadlock. The resource-allocation-graph algorithm models resource requests and allocations as a graph and only allows allocations that do not introduce cycles, representing unsafe states. Banker's algorithm is for systems with multiple instances of resources and also only allows allocations that keep the system in a safe state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
82 views12 pages

Chapter 7: Deadlocks: 7.5 Deadlock Avoidance

This document summarizes deadlock avoidance techniques, specifically the safe state approach and two algorithms: the resource-allocation-graph algorithm and Banker's algorithm. The safe state approach ensures that the system is always in a safe state where resources can be allocated without leading to a deadlock. The resource-allocation-graph algorithm models resource requests and allocations as a graph and only allows allocations that do not introduce cycles, representing unsafe states. Banker's algorithm is for systems with multiple instances of resources and also only allows allocations that keep the system in a safe state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

CHAPTER 7: DEADLOCKS

(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.

Figure 7.5: Safe, unsafe, and deadlock state spaces


To illustrate, we consider a system with 12 magnetic tape drives and three processes: , , and . Process
requires 10 tape drives, process may need as many as 4 tape drives, and process may need up to 9 tape drives.
Suppose that, at time , process is holding 5 tape drives, process is holding 2 tape drives, and process is
holding 2 tape drives. (Thus, there are 3 free tape drives.)

Maximum Needs Current Needs

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.

7.5.2 Resource-Allocation-Graph Algorithm


If we have a resource-allocation system with only one instance of each resource type, a variant of the resource-
allocation graph defined in Section 7.2.2 can be used for deadlock avoidance. In addition to the request and
assignment edges already described, we introduce a new type of edge, called a claim edge. A claim edge
indicates that process may request resource at some time in the future. This edge resembles a
request edge in direction but is represented in the graph by a dashed line. When process requests resource , the
claim edge is converted to a request edge. Similarly, when a resource is released by , the
assignment edge is reconverted to a claim edge . We note that the resources must be
claimed a priori in the system. That is, before process starts executing, all its claim edges must already appear in
the resource-allocation graph. We can relax this condition by allowing a claim edge to be added to the
graph only if all the edges associated with process are claim edges.
Suppose that process requests resource . The request can be granted only if converting the request edge
to an assignment edge does not result in the formation of a cycle in the resource-allocation
graph. Note that we check for safety by using a cycle-detection algorithm. An algorithm for detecting a cycle in this
graph requires an order of operations, where n is the number of processes in the system.
If no cycle exists, then the allocation of the resource will leave the system in a safe state. If a cycle is found, then the
allocation will put the system in an unsafe state. Therefore, process will have to wait for its requests to be
satisfied.

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.

Figure 7.6: Resource-allocation graph for deadlock avoidance

Figure 7.7: An unsafe state in a resource-allocation graph


7.5.3 Banker's Algorithm
The resource-allocation-graph algorithm is not applicable to a resource-allocation system with multiple instances of
each resource type. The deadlock-avoidance algorithm that we describe next is applicable to such a system but is
less efficient than the resource-allocation graph scheme. This algorithm is commonly known as the banker's
algorithm. The name was chosen because the algorithm could be used in a banking system to ensure that the bank
never allocated its available cash in such a way that it could no longer satisfy the needs of all its customers.
When a new process enters the system, it must declare the maximum number of instances of each resource type that
it may need. This number may not exceed the total number of resources in the system. When a user requests a set of
resources, the system must determine whether the allocation of these resources will leave the system in a safe state.
If it will, the resources are allocated; otherwise, the process must wait until some other process releases enough
resources.
Several data structures must be maintained to implement the banker's algorithm. These data structures encode the
state of the resource-allocation system. Let n be the number of processes in the system and m be the number of
resource types. We need the following data structures:
Available: Avector of length m indicates the number of available resources of each type. If Available[ j ] equals
k , there are k instances of resource type available.
Max: An matrix defines the maximum demand of each process. If Max[ i ][ j ] equals k , then process
may request at most k instances of resource type .
Allocation: An matrix defines the number of resources of each type currently allocated to each process. If
Allocation[ i ][ j ] equals k , then process is currently allocated k instances of resource type .
Need: An matrix indicates the remaining resource need of each process. If Need[ i ][ j ] equals k , then
process may need k more instances of resource type to complete its task. Note that Need[ i ][ j ] equals Max[
i ][ j ] − Allocation[ i ][ j ].
These data structures vary over time in both size and value.
To simplify the presentation of the banker's algorithm, we next establish some notation. Let X and Y be vectors of
length n . We say that if and only if for all . For example, if
and , then . if and .

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.

If no such i exists, go to step 4.


3.

.
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:

Allocation Max Available

ABC ABC ABC

010 753 332

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:

Allocation Need Available

ABC ABC ABC

010 743 230

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

An algorithm to recover from the deadlock

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.

If no such i exists, go to step 4.


3.

4. If , for some i , , then the system is in a deadlocked state. Moreover, if


, then process is deadlocked.

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:

Allocation Request Available

ABC ABC ABC

010 000 000

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.

Figure 7.9 Traffic deadlock for Exercise 7.1.


a. Show that the four necessary conditions for deadlock indeed hold in this example.
b. State a simple rule for avoiding deadlocks in this system.
7.2 Consider the deadlock situation that could occur in the dining philosophers problem when the philosophers
obtain the chopsticks one at a time. Discuss how the four necessary conditions for deadlock indeed hold in this
setting. Discuss how deadlocks could be avoided by eliminating any one of the four conditions.
7.3 A possible solution for preventing deadlocks is to have a single, higher-order resource that must be requested
before any other resource. For example, if multiple threads attempt to access the synchronization objects ,
deadlock is possible. (Such synchronization objects may include mutexes, semaphores, condition variables, etc.)
We can prevent the deadlock by adding a sixth object F . Whenever a thread wants to acquire the synchronization
lock for any object , it must first acquire the lock for object F . This solution is known as containment: The
locks for objects are contained within the lock for object F . Compare this scheme with the circular-wait
scheme of Section 7.4.4.
7.4 Compare the circular-wait scheme with the various deadlock-avoidance schemes (like the banker's algorithm)
with respect to the following issues:
a. Runtime overheads
b. System throughput
7.5 In a real computer system, neither the resources available nor the demands of processes for resources are
consistent over long periods (months). Resources break or are replaced, new processes come and go, new
resources are bought and added to the system. If deadlock is controlled by the banker's algorithm, which of the
following changes can be made safely (without introducing the possibility of deadlock), and under what
circumstances?
a. Increase Available (new resources added).
b. Decrease Available (resource permanently removed from system).
c. Increase Max for one process (the process needs more resources than allowed; it may want more).
d. Decrease Max for one process (the process decides it does not need that many resources).
e. Increase the number of processes.
f. Decrease the number of processes.

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

ABCD ABCD ABCD

0 01 2 0012 1520

1000 1750

1354 2356

0632 0652

0014 0656

Answer the following questions using the banker's algorithm:


a. What is the content of the matrix Need?
b. Is the system in a safe state?
c. If a request from process arrives for (0,4,2,0), can the request be granted immediately?
7.12 What is the optimistic assumption made in the deadlock-detection algorithm? How could this assumption be
violated?
7.13 Write a multithreaded program that implements the banker's algorithm discussed in Section 7.5.3. Create n
threads that request and release resources from the bank. The banker will grant the request only if it leaves the
system in a safe state. You may write this program using either Pthreads or Win32 threads. It is important that
access to shared data is safe from concurrent access. Such data can be safely accessed using mutex locks,
which are available in both the Pthreads and Win32 API. Coverage of mutex locks in both of these libraries is
described in “producer–consumer problem” project in Chapter 6.
7.14 A single-lane bridge connects the two Vermont villages of North Tunbridge and South Tunbridge. Farmers in
the two villages use this bridge to deliver their produce to the neighboring town. The bridge can become
deadlocked if both a northbound and a southbound farmer get on the bridge at the same time (Vermont
farmers are stubborn and are unable to back up.) Using semaphores, design an algorithm that prevents
deadlock. Initially, do not be concerned about starvation (the situation in which northbound farmers prevent
southbound farmers from using the bridge, or vice versa).
7.15 Modify your solution to Exercise 7.14 so that it is starvation-free.

You might also like