Deadlock
Deadlock
- Occurs when resources needed by one process are held by some other waiting
process.
Deadlock
not only occurs in OS.
Kansas
state legislature in the early 20th century passed the following
legislation:
"When
two trains approach each other at a crossing, both shall come to a full stop
and neither shall start up again until the other has gone. "
Assume
we have the following operating system:
1.
Finite
number of resources to be distributed among some number of competing processes
2.
Resources
may be of several types and there may be several instances of each
3.
When
a process requests a resource any instance of that resource will satisfy the
process
4.
Processes
can
a.
request
a resource
b.
use
the resource
c.
release
the resource
5.
A
set of processes is in a deadlock state when every process in the set is
waiting for an event that can be caused only by another process in the
set.
a.
Same
resource type - three tape drives,
three processes request a tape drive then they each request
another. Dining philosophers request
chopsticks held by another.
b.
Different
resource type - process A has a printer process B has a file, Each requests the
other's resource.
Four
Necessary Conditions for Deadlock
1.
Mutual
exclusion: At least one resource is not
sharable, i.e. can only be used by one process at a time
2.
Hold
and wait: A process holds at least one
resource and requests resources held by other processes
3.
No
preemption: resource cannot be preempted, it must be voluntarily released by
the process.
4.
Circular
wait: Given a set of processes { P1,
P2, P3, …Pn} P1 has a resource needed by P2, P2 has a resource needed by P3, …,
Pn has a resource needed by P1.
System
resource-allocation graph
G =
(V,E) where V is a set of vertices and E is a set of edges.
The
set of vertices is partitioned into Processes and Resources. A resource-allocation graph is a directed
graph where an edge from process Pi to resource Ri indicates that Pi has requested Ri (request edge). An edge
from Ri to Pi indicates that Ri has been allocated to Pi (assignment edge).
When
drawing the graph, processes are represented by circles and resources by
squares. Multiple instances of a
resource are represented by a dot in the square.
When
a process requests a resource a request edge is drawn. When the resource is allocated, the resource
edge becomes an assignment edge.
Resource edges points to the resource square, but assignment edges are
from the dots within the square.
Resource
allocation graph, no deadlock
If
the graph contains no cycles, then there is no deadlock
If
the graph contains a cycle then a
deadlock condition may exist.
Resource allocation graph
with deadlock.
Resource allocation graph
with cycle and no deadlock.
P4 can release an instance
of R2 and P3 will be assigned the resource
How
can we handle deadlocks?
1.
Try
to prevent them from happening
2.
After
system is deadlocked employ some mechanism to detect the deadlock and then
recover from deadlock.
3.
Ignore
the problem, theoretically rare, and pretend deadlocks never occur (UNIX) Since deadlocks are infrequent this may be
cheaper alternative
Deadlock
Prevention - Make sure one of the 4 necessary conditions for deadlock doesn't
hold.
1.
Mutual Exclusion - some resources are sharable. Some cannot be shared or be made sharable. A printer can be used by only one process at
a time.
2.
Hold and Wait - Whenever a process requests one resource make sure it is not
holding another resource.
·
method
1 - request all resources before it begins execution,
·
method
2 - request resources only when process has none, it may request some
resources, use them and then release all resources.
·
Downside
- method 1 - assume process needs to copy file from tape to disk and then
print. It will be holding printer
entire time even though it needs it only at the end.
·
Downside
method 2 - process can request tape and disk, release these and then request
printer. Only if file remains on disk!!
No guarantee.
·
Poor
resource utilization, chance of starvation
3.
No Preemption-
·
method
1 - process holds resources and needs another resource that is not in use. Process must release all resources, then
waits on released resources in addition to the needed one
·
method
2 - check if resources are available when requested, if so allocate them. If not check if they are allocated to
another process that is waiting for resources.
If so, preempt the desired resources from the waiting process and
allocate them to the requesting process.
If the requested resource is not available, then the process waits. It can then be preempted by another process
in the same way.
4.
Circular Wait
·
Place
an ordering on the resource types.
Processes have to request resources in increasing order of numbering
·
Alternately,
when a process requests a resource of a lower number, resources of higher
number are deallocated.
deadlock
prevention can have the side effect of reduced system throughput and low device
utilization.
Deadlock
Avoidance
Processes
declare in advance what its maximum resource usage will be. Use this a priori
information about a process' resource needs to make sure a system never enters
deadlock. (deadlock avoidance
approach) Dynamically makes sure that
the circular wait conditions doesn't exist.
Def.
A system is in a safe state if it can allocate resources to each process, in
some order and avoid deadlock.
A
system is a safe system if there exists a safe sequence. A sequence of processes <P1, P2,
P3, …, Pn > is a safe sequence for the current
allocation state if for each Pi, the resources that Pi
can still request can be satisfied by the currently available resources plus
the resources held by all the Pj, with j<i.
In
this state if a process requests a resource and it isn't currently available,
it can wait until the other processes finish and then use the resources. The next process in the sequence can finish
in the same manner. If this doesn't
happen the state is unsafe. Unsafe
states may lead to deadlock.
|
Maximum
Needs |
Current
Needs |
P0 |
10 |
5 |
P1 |
4 |
2 |
P2 |
9 |
2 |
If
system has 12 tape drives we are in a safe state because, < P1, P0,
P2> satisfies the safety
condition.
If
we are in the above state and grant P2 1 more tape drive the system
is no longer safe.
Resource-Allocation
Graph Algorithm
Used
only when there is one instance of each resource.
Request
edges, assignment edges, new edge called claim edge.
Claim
edge from process to resource indicate process may request that resource some
time in the future. Represented by a
dashed arrow. Direction is the same as
a request edge.
When
process requests resource, claim edge becomes request edge. When process releases a resource, assignment
edge becomes claim edge.
If a process requests a
resource, the request can be granted only if converting the request edge to an
assignment edge does not result in a cycle in the graph.
Safe, but if P2 were to
request R2 then we would not be in a safe state
Banker's
Algorithm
Used
for multiple resource instances.
1.
Processes
must declare maximum instances of each resource that it will need. Number can't exceed the total number of
resources in the system
2.
Process
will be allocated resources only if this results in a safe state. Otherwise process waits until some other
process releases resources.
Given
two vectors (arrays), X and Y of length n, X <= Y iff X[i] <= Y[i] for
all i = 1,2,…,n. i.e. if X = (1,7,3,2) and Y = (0,3,2,1) then Y
<=X.
int
available [j] //each array position
indicates the number of instances of
// resource Rj
int
max [n][m] // Rows represent processes, columns resources, value is
//maximum number of
resource Rj needed by process Pi
int
allocation [n][m] //number of resources of each type allocated to each
//process
int
need [n][m] //remaining resource needs
of each process.
Safety
Algorithm:
<step
1>
int
work[m]
int
finish [n]
work
= available;
for
(i = 0; i < n; i++) finish [i] = false;
<step
2 >
Find
i such that both
finish
[i] = false
needi
<= work //let needi be
the need vector for process Pi
if i
doesn't exist goto step 4.
<step
3>
Work
= work + allocation
finish[i]
= true
go
to step 2
<step
4>
If
finish[i]
= true for all i then the system is in a safe state.
requires
order m x n2 operations to decide whether a state is safe
Resource
Request Algorithm
Step
1
if requesti < needi
goto step 2, else error request is above maxium
step
2
if requesti < available go to step 3, else
process waits
step
3
System
pretends to allocate resource
available
= available - request
allocation = allocation + request
need
= need - request
If
this results in a safe state, then resource is allocated, else it is not.
|
Allocation |
Max |
Available |
|
A B C |
A B C |
A B C |
0 |
0 1 0 |
7 5 3 |
3 3 2 |
1 |
2 0 0 |
3 2 2 |
|
2 |
3 0 2 |
9 0 2 |
|
3 |
2 1 1 |
2 2 2 |
|
4 |
0 0 2 |
4 3 3 |
|
|
Need (Max - Allocation) |
|
A B C |
0 |
7 4 3 |
1 |
1 2 2 |
2 |
6 0 0 |
3 |
0 1 1 |
4 |
4 3 1 |
System
is safe. (P1, P3, P4, P2, P0 ) is a
safe sequence.
What
happens if P1 requests one of A, two of type C (1 0 2)
We
now have the following state:
|
Allocation |
Max |
Available |
|
A B C |
A B C |
A B C |
0 |
0 1 0 |
7 5 3 |
2 3 0 |
1 |
3 0 2 |
0 2 0 |
|
2 |
3 0 2 |
9 0 2 |
|
3 |
2 1 1 |
2 2 2 |
|
4 |
0 0 2 |
4 3 3 |
|
This
is safe since <P1, P3, P4, P0, P2>
is a safe sequence
P4
requests 3 3 0?
P0
requests 0 2 0?
Deadlock Detection
In
absence of deadlock prevention and avoidance, we need deadlock detection.
Consists
of two things: algorithm to detect deadlock, algorithm to recover from
deadlock.
detection
- recovery includes the overhead incurred by recovery from deadlock and
algorithms.
Wait-for
graph - Used for single resource instances. - Obtained from resource-allocation
graph by removing resource nodes and deleting appropriate edges.
int
available [m] //each array position
indicates the number of instances of
// resource Rj
int
request [n][m] // indicates current request of each process
int
allocation [n][m] //number of resources of each type allocated to each
//process
<step
1>
int
work[m]
int
finish [n]
work
= available;
for
(i = 0; i < n; i++) if allocationi != 0 finish [i] = false else finish[i] = true
<step
2 >
Find
i such that both
finish
[i] = false
requesti
<= work //let requesti
be the request vector for process Pi
if i
doesn't exist goto step 4.
<step
3>
work
= work + allocation
finish[i]
= true
go
to step 2
<step
4>
If
finish[i]
= false for all i then the process Pi is in deadlock.
|
Allocation |
Request |
Available |
|
A B C |
A B C |
A B C |
0 |
0 1 0 |
0 0 0 |
0 0 0 |
1 |
2 0 0 |
2 0 2 |
|
2 |
3 0 3 |
0 0 0 |
|
3 |
2 1 1 |
1 0 0 |
|
4 |
0 0 2 |
0 0 2 |
|
Not
deadlocked p0, p2, p3, p1, p4 is a safe sequence
|
Allocation |
Request |
Available |
|
A B C |
A B C |
A B C |
0 |
0 1 0 |
0 0 0 |
0 0 0 |
1 |
2 0 0 |
2 0 2 |
|
2 |
3 0 3 |
0 0 1 |
|
3 |
2 1 1 |
1 0 0 |
|
4 |
0 0 2 |
0 0 2 |
|
P2
makes additional request for 1 more item.
Now
deadlocked.
Overhead
in running detection algorithms. Run
each time a request is made?? Run as
often as deadlock is to occur. (Once
per hour, or when CPU utilization drops below 40%.
Recover
from deadlock.
Tell
operator, he decides who shall live and who shall die!
Abort
all deadlocked processes - cost is high.
All work done by processes is lost.
Abort
one at a time until deadlock no longer exists - need to run deadlock detection
algorithm after each process is aborted - high overhead this way.
Resource Preemption –Choose a
blocked resource
–Preempt it (releasing its
resources)
–Run the detection algorithm
–Iterate if until the state
is not a deadlock state
Problem: Starvation – same process may always be picked as victim, include number of
rollback in cost factor.