- Introduction
processes are blocked, waiting on events that could never happen
different from starvation ( the associated resource is in continuous use )
Four necessary conditions for deadlock:
- mutual exclusion
- hold and wait
- no preemption
- circular wait
e.g. Resources are two books: Java Programming, OS Principles,
need the two books to finish project
- Deadlock handling strategies
deadlock prevention, avoidance, detection, recovery
- Resource graph for single-unit resource type
cycle => deadlock
deadlock => cycle
- Graph-theoretic model
reusable resource -- can be used again and again ( e.g. CPU, main-memory, I/O devices )
consumable resource -- vanish as a result of its use ( e.g. messages, signals )
- Created (produced) by a process
- Destroyed (consumed) by a process
- Operations: request/receive (implies consume), produce/send
- Deadlock may occur if the receive operation can block
- Potential deadlock situations are more difficult to detect, and reproduce, by testing
resource access -- can be exclusive or shared
General resource system
- nonempty set of processes P = {
P1, P2, P3, ..., Pn}
- nonempty set of resources G = {
R1, R2, R3, ..., Rm}
G =
Gr ∪
Gc
reusable consumable
Gr ∩
Gc
= Ø ( disjoint )
- for every reusable Ri
ti = |Ri| = # of units of resource of type i
≥ 0
- for every consumable Ri
there exists subset R C P
producers of Ri
consumable resource -- concentric rectangle
process -- circle
O
General resource graph
a bi-partite directed graph with set of nodes:
P =
{ P1, P2, P3, ..., Pn}
G =
{ R1, R2, R3, ..., Rm}
available units vector
( a1, a2, a3, ..., am)
A bi-partite graph is a graph whose nodes can be divided
into two disjoint sets such that two adjacent nodes cannot come from the
same set.
diagrams
for every reusable resource Ri:
- # of assignment edges #( Ri, * ) ≤ ti
- ai = ti - #(Ri, * )
- a process cannot request more than the total number of
units of a resusable resource
#(Pj, Ri ) ≤ ti - #(Ri, Pj )
for every consumable resource Ri
- ( Ri, Pj ) exists iff Pj is a producer of Ri
- ai ≥ 0
if #( Pi, Rj ) > aj => pi blocked ( more requests than available resources )
- Reduction of Resource Graph
If a process's resource requests can be granted, then we say that
the graph can be reduced by that process
( i.e. the process is allowed to complete its execution and return
all its resources )
consider reusable resources only
If a graph can be reduced by all the processes, then there is
no deadlock.
If a graph cannot be reduced by all the processes, the
irreducible processes constitute the set of deadlock
processes in the graph
An example of reduction of an RAG ( Resource Allocation Graph )
Example of RAG with loop but no deadlock
Now if we consider both reusable and consumable resources:
graph completely reducible => state deadlock free
but deadlock free may not => graph completely reducible
necessary and sufficient conditions for deadlock
A state is an expedient state if all processes having
outstanding requests cannot be granted
if node only has incoming edges => sink
Definition
A knot K in a graph is a nonempty set of nodes such that
for every node x in K, all nodes in K and only the nodes in K
are reachable from x.
( all x, all y ∈ K => x → y ) AND ( all x ∈ K, some z, such that x → z => z ∈ K )
Example
Question: Any knot in the above figure?
Theorem
- A cycle is a necessary condition for a deadlock.
- If the graph is expedient, then a knot is a sufficient condition for deadlock.
System with only consumable resources
claim-limited graph
- each resource has 0 available units
- it has a request edge ( pi, Rj ) iff
Pi is a consumer of Rj
This claim-limited graph cannot be reduced
Theorem:
A consumable resource only system is deadlock free if its claim-limited
graph is completely reducible.
But a system may fail the claim-limited graph reducibility test, and
still be free from deadlock. Example: Both P1 and P2 are
producers and consumers.
| Process P1 | | Process P2 |
.
down ( mutex );
critical_section();
up ( mutex );
.
loop
|
|
.
down ( mutex );
critical_section();
up ( mutex );
.
loop
|
- Deadlock Avoidance
requires that the maximum resource requirement of a process be
known at every state during its execution ( claim of the
process )
resource is granted only if the resulting state is safe
a state is safe if there exists at least one sequence
of execution for all processes such that all of them can run
to completion
Trajectory Diagram
A deadlock path
- P2 requests R2
- The OS grants the request of P2
- P1 requests R1
- The OS grants the request of P1
- P2 requests R1
- The OS cannot grant the request of P2, because R1 is locked.
- P1 requests R2
- The OS cannot grant the request of P1, because R2 is locked.
- No further progress is possible, i.e. we have a deadlock.
An avoidance path
- P2 requests R2
- The OS grants the request of P2
- P1 requests R1
- The OS postpones granting the request of P1, because it would lead to an unsafe state.
- P2 requests R1
- The OS grants the request of P2
- P2 releases R1
- The OS grants the request of P1 for R1
- P1 requests R2
- The OS cannot grant the request of P1, because it R2 is still locked by P2.
- P2 releases R2
- The OS grants the request of P1 for R2
- P1 releases R2
- P1 releases R1
Question: What is the difference between a safe state and a deadlock-free state?
How do we know a state is safe?
- Start in the given state
- Simulate running each process to completion,
by allocating its maximum resource requirements,
and then releasing all resources
- If all processes can complete, the state is safe
Habermann's Algorithm ( generalization of Dijkstra's Algorithm )
Max-Avail matrix A =
( a1 a2 ... am )
where ai = ti = |Ri|
| Max-Claim matrix B = |
 |
| b 11 |
b 12 |
... |
b 1m |
| b 21 |
b 22 |
... |
b 2m |
| . |
. |
. |
. |
| b n1 |
b n2 |
... |
b nm |
|
 |
= |
 |
|
 |
where bij = max number of units of Resource Rj that will ever be held by process Pi
| Allocation matrix C = |
 |
| c 11 |
c 12 |
... |
c 1m |
| c 21 |
c 22 |
... |
c 2m |
| . |
. |
. |
. |
| c n1 |
c n2 |
... |
c nm |
|
 |
= |
 |
|
 |
where cij = number of units of Resource Rj that
are currently held by process Pi
- all k, Bk ≤ A ( no process can claim more units of Resources than are available )
- C ≤ B ( no process attempts to request more resources than its maximum claim )
 |
n k=1 |
Ck ≤ A ( never allocate more resources than are available ) |
- Available matrix D:
| D = |
( d1 |
d2 |
... |
dm ) |
= |
A - |
 |
n k=1 |
Ck |
di = number of units of Resourc Ri available in current state
- Need matrix E:
| Need matrix E = |
 |
| e 11 |
e 12 |
... |
e 1m |
| e 21 |
e 22 |
... |
e 2m |
| . |
. |
. |
. |
| e n1 |
e n2 |
... |
e nm |
|
 |
= B - C = |
 |
|
 |
- Request matrix F:
| Request matrix F = |
 |
| f 11 |
f 12 |
... |
f 1m |
| f 21 |
f 22 |
... |
f 2m |
| . |
. |
. |
. |
| f n1 |
f n2 |
... |
f nm |
|
 |
= |
 |
|
 |
- tentative state:
Suppose we grant all requests and see what would happen.
| D ← D - Fi | ( avialable - requests ) |
|
| Ci ← Ci + Fi |
( allocated + requests ) |
|
Ei ← Ei - Fi |
( need - requests ) |
The request is granted only if the tentative state is a safe state
- Safe-State Check Algorithm
- Pick an unfinished process Pi such that Ei
≤ D (i.e more resources available than needed by Pi ). If no such process exists, go to Step 3.
- D ← D + Ci. Tag Pi as finished. Go to step 1.
- If all processes are tagged finished, the system state is safe; otherwise it is not safe.
If the system is not safe, the request is blocked and the system state is reset by
D ← D + Fi
Ci ← Ci - Fi
Ei ← Ei + Fi
|
In addition, a process tagged with finished in step 2 is reset by:
D ← D - Ci
and retag Pi as unfinished.
- Example
max-Avail A = ( 2 4 3 )
| Max-Claim B = |
 |
|
 |
| Allocation C = |
 |
|
 |
Available D = ( 0 1 1 )
| Need E = |
 |
|
 |
Suppose process P1 makes a request
F1 = ( 0 0 1 )
The tentative state would be:
Available D = ( 0 1 0 )
| Allication C = |
 |
|
 |
| Need E = |
 |
|
 |
In this state, P3 can complete because E3 ≤ D
returning ( 1 0 1 ) to the available pool of resources,
D = ( 1 1 1 )
Thus, the outstanding needs of both P1 and P2
can be satisfied and consequently the tentative state resulting from
the request P1 is safe and the request F1 of
P1 can be granted.