Skip to main content
Operating Systems

Deadlocks

Published: 2026-08-15
Level: postgraduate
Audience: Postgraduate students studying Operating Systems

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • Deadlock: when processes wait on each other — covered in Lecture 1
  • Resource allocation — covered in Lecture 2 (the operating system as resource allocator)
  • Processes and process states — covered in Lecture 3 (the blocked state: a process waiting for an event)
  • Starvation — covered in Lecture 6 (a process waiting indefinitely while others make progress)

9.1 Deadlocks: The Basic Picture

Hook — two people, two files, zero progress. Suppose Alice is holding file A and wants file B, while Bob is holding file B and wants file A. Alice will not give up A until she gets B; Bob will not give up B until he gets A. Neither can move, and neither will back down. Every process in a deadlock is exactly like Alice or Bob: it is holding a resource and waiting to acquire a resource that is held by another process, forever. This lecture studies when that happens, how to recognize it in a picture, and what an operating system can do about it.

9.1.1 Holding and Waiting

A deadlock is a state in which a set of processes is blocked because each process holds a resource and waits for another resource that is held by some other process in the set. The simple setup goes like this: take a list of processes, each holding a resource, each in need of another resource that is not free because some other process holds it. For example, if P1 is holding R1 and is in need of R2, while P2 is holding R2 and is in need of another resource held by P1, then every participant is stuck: each is holding a resource and each is waiting to acquire a resource. The two phrases holding a resource and waiting to acquire a resource are the heart of the topic — they were emphasized as very, very, very important, because a deadlock is exactly the combination of these two actions across a closed circle of processes.

The definition, unpacked. Formally, a set of processes is deadlocked when every process in the set is blocked waiting for an event (usually the release of a resource) that can only be triggered by another blocked process in the same set. Because every process waits on the set, and nothing outside the set can release the needed resource, the blocking is permanent — no event will ever fire. Two details worth keeping:

  • A process may hold several resources, not just one; what matters is that it holds at least one while waiting.
  • A process may hold nothing at all and still be part of a deadlock, as long as it is waiting for a resource held by another process that is itself waiting. Holding is not a requirement for being stuck — waiting in the circle is.

The block diagram of the idea shows a set of processes with two resources, resource one and resource two. Resource one is assigned to process one, but process one is waiting for resource two; resource two is assigned to process two, which is waiting for resource one. Each process is holding a resource and waiting to acquire a resource — the same two actions as before. Draw the picture the way the arrows go: R1 → P1 (P1 holds R1), P1 → R2 (P1 wants R2), R2 → P2 (P2 holds R2), P2 → R1 (P2 wants R1). Follow the arrows from any point and you come back to where you started: the arrows form a closed loop, a cycle, and that cycle is the signature of a deadlock. This cycle can form with any number of processes and any number of resources. The classic small example is a system with two disk drives: P1 is holding one disk drive, P2 is holding the other, and both need one more drive. Only two drives exist, each is held, and there is no way forward — that is one concrete deadlock.

Worked example — two disk drives. A system has exactly two disk drives, D1 and D2, and two processes.

  1. P1 requests and is allocated D1. Now P1 holds D1.
  2. P2 requests and is allocated D2. Now P2 holds D2.
  3. P1 requests D2 (it still needs a second drive for its job). D2 is held by P2, so P1 waits.
  4. P2 requests D1 (it also needs a second drive). D1 is held by P1, so P2 waits.

The system is now stuck. P1 cannot release D1 until it finishes, it cannot finish without D2, and D2 is with P2; P2 is in the mirror-image situation. Every arrow points to a resource held by the other process: holding + waiting + holding + waiting, around a cycle. No process can make progress, and nothing will ever change. This is a deadlock.

Sense-check: count the resources — two drives, both allocated, zero free. Any request for a drive must wait, and both waiting processes are the holders of the only drives. There is no one left who can release anything, so the wait is permanent.

9.1.2 A Real-World Picture: The Traffic Jam

Real-world: the famous everyday example is a traffic jam near a railway track. Vehicles are coming from this side and also from the other side, and both streams have occupied the same stretch of track, so no one can go either this way, that way, or the other way. Every vehicle is stuck at a particular point because every path is held by some other vehicle. We can treat the road as a resource that is held by the vehicles, and each vehicle as one of the processes, each in need of the resource — the road. The system is in a deadlock, and whatever we do to prevent or avoid the deadlock in traffic applies to our set of processes as well.

Mapping the analogy to the system. The traffic jam is not a loose comparison — it is the same structure:

Traffic jam Deadlock in a system
A stretch of road A resource (for example, a disk drive)
A vehicle A process
A vehicle occupying a stretch of road A process holding a resource
A vehicle waiting for the stretch ahead to free up A process waiting to acquire a resource
Two streams blocking each other on one track Two processes each holding what the other needs

The professor's point: techniques that break the traffic jam are, in spirit, the same as the techniques of deadlock prevention and avoidance — remove one vehicle from the jam (preempt a resource), make one vehicle back up and release the road (release-and-restart), or forbid vehicles from entering the single track until the other side is clear (avoid entering an unsafe situation). The analogy breaks in one place: a real driver can be coaxed to back up by a human traffic officer, while a deadlocked process has no outside help — the operating system itself must intervene, which is why we need algorithms, not patience.

9.1.3 Finite Resources, Resource Types, and Instances

A deadlock can only occur with finite resources — this is why the discussion is confined to them. Infinite resources would never run out, so no process would ever have to wait, and no deadlock could form. Wait, in this course, is always about a scarce resource: the resource is there in limited supply, everyone wants it, and someone holds it. Finite resources include: the memory space (how many processes have occupied space, and whether enough free space remains for another process), the number of CPUs, the number of files, and the number of devices such as printers. Say three printers exist and more than three processes want one: each process may hold one printer now, and later may need another instance of the same resource type — but it cannot get it because the fourth process holds it, and so on. We can imagine any arrangement in which a process is holding and waiting to acquire a resource.

A distinction must be kept straight: the resource type is the name of the category (printer, CPU), while the number of instances is how many copies of that type exist. "Three printers" means the resource type is printer and the number of instances is three. "CPU is three" means the resource type is CPU and the number of instances is three. Getting the two levels separate makes the later graphs and tables readable — every resource type is one square in the graph, and every instance is one dot inside that square.

Type versus instance, with a number. An instance (a single copy of a resource type) is what a process actually holds. If the type "printer" has 3 instances, then three different processes can each hold one printer at the same time. A fourth process asking for a printer gets nothing and waits. In the banker's algorithm (Section 9.6) this distinction becomes data: counts free instances of type , and counts instances of type held by process .

9.1.4 The Request–Use–Release Cycle

Whenever a process has to use a resource, it has to request it, then use it, and then release it. Those three steps are the only way to use a resource safely, and they were stated as things to remember. The same three steps appear in every kind of resource, with different vocabulary: for a device, request the device, use it, release it; for a file, open it in order to use it, then close it; for memory, free space is allocated, the space is used, and then the space is freed.

World Step 1: request Step 2: use Step 3: release
Device request the device use the device release the device
File open the file read or write close the file
Memory allocate free space use the space free the space

Why the cycle matters for deadlock. These three steps explain where a deadlock gets its chance: the window between request and release is exactly the window in which a process holds something while waiting for something else. If every resource were requested, used, and released one at a time with nothing held in between, deadlock would be impossible. The trouble starts when a process holds resource A, has not yet released it, and asks for resource B — that single act is the "hold" part of hold and wait, the second of the four necessary conditions studied in Section 9.2.

9.1.5 The Same Problem in Synchronization

The dining philosophers problem is the same problem wearing a different costume. The chopsticks are finite, and each philosopher needs two chopsticks — one from the left hand side and one from the right hand side — in order to eat. A philosopher may fail to acquire both because the left chopstick is already held by a neighbor, in which case the philosopher has to wait. In that situation a deadlock may occur, exactly as it can with any finite number of resources: if every philosopher picks up the left chopstick first and then waits for the right one, each is holding one chopstick and waiting for a chopstick held by a neighbor — a perfect circle of holding and waiting. The producer-consumer problem and the reader-writer problem share the same underlying worry: when a limited resource is shared, processes can end up waiting on each other forever. The connection to synchronization also shows up again when the four conditions are explained — mutual exclusion, the first condition, is the very guarantee that the critical section problem fought for.

Common pitfalls in this section.

  • "A process must hold a resource to be part of a deadlock." Wrong — a process holding nothing can be stuck in the circle, waiting for a resource held by someone who is waiting for it in return. It is the waiting cycle, not the holding, that blocks everyone.
  • Mixing up type and instances. "Printer = 3" is not a resource called "3 printers" — it is one type with three instances. Every instance is a separate unit that one process can hold. This confusion breaks graph reading and banker's algorithm tables later.
  • Calling any long wait a deadlock. A process waiting for an I/O device or a slow CPU is normal and temporary. Deadlock is permanent blocking: no process in the circle can ever release the needed resource, because each of them is waiting too.
  • Thinking infinite resources can deadlock. If a resource never runs out, no request ever has to wait, so the holding-and-waiting circle never forms. Deadlock lives entirely in the world of finite resources.

Visual intuition. Picture the two-disk-drive example as a diagram: two circle nodes (P1, P2) and two square nodes (D1, D2). Edges: D1 → P1, P1 → D2, D2 → P2, P2 → D1. The four arrows form a closed loop — start anywhere, follow arrows, and return to the start. The takeaway: a closed loop of holding and waiting arrows is the picture of a deadlock; this is exactly the cycle that the resource allocation graph of Section 9.3 will look for, on a much larger scale.

Recap + bridge. A deadlock is a set of processes, each holding a resource and waiting to acquire a resource held by another member of the set — the "holding and waiting" pair is the heart of the topic, and the traffic jam is its everyday face. Next we ask: what exactly has to be true for such a circle to form? The answer is the four necessary conditions of a deadlock.

Real-world connection: deadlocks are not a classroom fiction. Database engines like MySQL (InnoDB), PostgreSQL, and Oracle detect lock-wait circles between transactions and resolve them by rolling one transaction back — a real deployment of the detection-and-recovery idea met in Section 9.4. Distributed file systems and cloud schedulers face the same circle when two nodes each hold a lock the other node needs. The same structure also appears far from computing: two ships crossing a narrow channel, or two processes on a factory line each waiting for the other's finished part. Wherever a finite resource is shared, the holding-and-waiting circle can appear, and the algorithms of this module are how systems break it.

9.2 The Four Necessary Conditions of a Deadlock

A deadlock has four characterizations (also called necessary conditions). These are the features that must all be present for a deadlock to occur, and each one gets a careful definition. Think of them as the ingredients of a recipe: the dish (deadlock) is only on the table when every single ingredient is in the pot at the same time.

Hook — what makes the traffic jam permanent? In the railway-track jam, why can no vehicle move? Because (1) the track is used by only one vehicle at a time, (2) each vehicle holds its position while wanting more road, (3) nobody can be moved off the track by force, and (4) the vehicles are arranged in a circle. Four features, all present at once. The same four features, restated for processes and resources, are the four necessary conditions of a deadlock — memorize them, because the entire deadlock module is organized around them.

9.2.1 Mutual Exclusion

Mutual exclusion is the condition that only one process at a time can use a resource. This is the same idea used when processes are synchronized: the resource is mutually exclusive, so any other process that arrives must wait for the resource. Without mutual exclusion, several processes could use the same resource at once, and the data they share would become inconsistent. If all the processes try to access a particular resource at the same time, a race condition occurs and the data is no longer consistent. This is the situation seen earlier in the critical section problem, the producer-consumer problem, and the reader-writer problem, and it is condition number one for a deadlock.

Formal statement. A resource is non-shareable if at most one process may hold it at a time. When process holds a non-shareable resource and process requests it, is forced to wait until releases it. That enforced waiting is what makes deadlock possible: mutual exclusion guarantees that some requests will be refused while a resource is busy. If a resource were shareable (a read-only file, for example), several processes could use it together and no one would ever wait for it — and a resource no one waits for cannot be part of a deadlock.

9.2.2 Hold and Wait

Hold and wait means a process is holding at least one resource and is in need of additional resources, so it is waiting to acquire another resource that is held by other processes. The process is doing both things at once: holding something it already has, and waiting for something it still needs. This is the second characterization of a deadlock.

Why "and" is the key word. A process that only holds (and never asks for more) finishes and releases — no problem. A process that only waits (holding nothing) blocks but blocks nobody else — also no problem. The deadlock ingredient is the combination: holding while waiting. Because the process keeps its old resources while asking for new ones, the resources it holds stay out of circulation, and the process it is waiting on may in turn be waiting for exactly those held resources.

9.2.3 No Preemption

No preemption means a resource held by a process can be taken away only voluntarily — the process itself must release it, and normally it releases only after completing its task. If there is no preemption, a process keeps on holding its resource, no other process can use that resource, and a deadlock can occur. The condition to watch for is the absence of preemption: the resource cannot be forcibly reclaimed while the holder still needs it.

Preemption is the opposite of being stuck. To preempt a resource means to take it away from its holder without the holder's consent — the way the CPU scheduler takes the processor away from a running process. Deadlock needs the no preemption condition: if an operating system could simply seize resource from the process waiting for , the circle could be cut open at any moment. Preemptable resources (CPU registers, memory pages that can be saved and restored) can be yanked away cheaply; a printer or a tape drive cannot, because its state cannot be captured and replayed.

9.2.4 Circular Wait

Circular wait is the situation in which the waiting processes form a ring. Starting from P0, P1, and so on up to Pn, the next process is again P0. Concretely: P0 is waiting for a resource held by P1, P1 is waiting for a resource held by P2, and so on until the last one, Pn, which is waiting for a resource held by P0. The waiting goes around in a circle, and when that happens a deadlock will occur. This is the fourth characterization.

The ring, drawn. Write the waiting chain as a sequence of arrows:

where means "process waits for resource " and means "resource is held by process ". The chain of arrows returns to its starting process: a closed ring. Visually, picture people seated in a circle, each holding the gift the person on the left wants — nobody can pass a gift without receiving one first. Note that circular wait is a stronger form of hold and wait: a ring of waiting processes automatically implies that every process in the ring holds something (the resource the previous process wants) while waiting. This is why the four conditions are not fully independent, yet it is still useful to study each one separately, because each suggests a different prevention strategy.

9.2.5 All Four Must Hold at the Same Time

These four are necessary conditions, and the rule to remember is that all four must occur simultaneously before we can say a deadlock has occurred. Even if one of them is not present, we cannot say for sure that a deadlock will occur — there may be chances of a deadlock, but it is not the deadlock yet. The simultaneity was stressed twice: not one condition now and another later or thereafter — no, all four at the same time. This is the kind of statement you should not forget. In real time, if the number of resources is limited and the number of processes that want to use them is larger, the chances for a deadlock exist — but again, only mutual exclusion alone is not enough; all four conditions must occur simultaneously.

Necessary versus sufficient. "Necessary" means: no deadlock without it — if even one condition is missing, there is definitely no deadlock. "Sufficient" means: with it, a deadlock is guaranteed. The four conditions together are necessary and sufficient for a deadlock: all four holding at once is the exact definition of the deadlocked state. The safest phrasing to remember: one condition missing ⟹ no deadlock; four conditions present, all at once ⟹ deadlock. This necessary/sufficient vocabulary returns with full force in Section 9.3, where a cycle in a graph is necessary (and, with single instances, sufficient) evidence of a deadlock.

Worked check — the two-disk-drive system against all four conditions. Take the two-drive example from Section 9.1 and verify each condition:

Condition In the two-drive system Holds?
Mutual exclusion Only one process can hold a drive at a time Yes
Hold and wait P1 holds D1 while waiting for D2; P2 holds D2 while waiting for D1 Yes
No preemption Neither process can be forced to give up its drive Yes
Circular wait P1 waits for P2's drive; P2 waits for P1's drive — a two-process ring Yes

All four hold simultaneously, so this is a genuine deadlock. Now remove just one ingredient: suppose the operating system could preempt a drive. At the moment P1 asks for D2, the system seizes D2 from P2 and gives it to P1 — the "no preemption" box becomes No, and the deadlock disappears even though the other three conditions still hold. One missing condition is enough to kill the deadlock, which is exactly what the prevention strategies of Section 9.5 exploit.

Sense-check: the table says three conditions can hold while the fourth fails, and the system survives. The claim "all four must hold simultaneously" is therefore consistent with "each single condition is necessary".

Visual intuition. Picture the four conditions as four locked doors on a corridor. Any one door open lets you walk through (no deadlock); all four shut at the same moment and you are trapped. In graph terms, mutual exclusion makes edges, hold and wait plus no preemption keep the edges alive, and circular wait closes the edges into a loop — the "closed loop" of arrows from Section 9.1.1 is precisely circular wait in picture form.

9.2.6 Student Questions and Answers

Q: If a process needs three resources and it is already holding two of them, how does mutual exclusion apply? Each of the three resources is one it needs; as of now it holds only two. If the third is available it can acquire it, but if the third is held by some other process it has to wait. A: Mutual exclusion means at a time only one process can use a resource. If another process wants to use that resource, it has to wait. This is exactly what we saw in the critical section problem: the critical section is a section of code present in every process, but not all processes can use their critical section at the same time — only one process can. If all processes have to read it, that is fine; but if any modification or update has to take place, the process must first acquire permission to enter the critical section, and only then can it use it. Mutually exclusive means that even if any number of processes exist, mutual exclusion is what keeps them synchronized; without it the data becomes inconsistent. If all processes try to access a particular resource and update it, a race condition occurs. The producer-consumer problem and the reader-writer problem show the same thing. In real time, consider a printer, a DVD drive, or any I/O device: those resources are limited, and if the number of processes that will use a resource is greater than the number of resources, the chances for a deadlock exist — but all four conditions must still occur simultaneously, not mutual exclusion alone.

Real-world connection: the four conditions are the checklist engineers actually use. MySQL's InnoDB storage engine builds a "wait-for" picture of transactions holding row locks and prints the exact circular chain when it aborts a transaction — that chain is condition four made visible. Deadlock monitors in database engines and in the Java virtual machine's lock manager work by watching for the ring while the other three conditions are taken for granted. If you can name which condition a real system violated, you can name the mechanism that fixed it.

Common pitfalls in this section.

  • Believing one condition is the deadlock. Mutual exclusion alone, or circular wait alone, is not a deadlock — only all four at the same instant. Many students see a cycle of waiting processes and declare "deadlock!"; Section 9.3 will show that even a graph cycle can be harmless when resources have multiple instances.
  • Confusing "necessary" with "sufficient". "All four necessary" does not mean "any one of them is enough"; it means "all four are required". The word necessary describes a requirement, not a guarantee.
  • Forgetting simultaneity. A system can have mutual exclusion in the morning and circular wait in the evening — no deadlock, because the four conditions never coexisted. The examination statement to expect is precisely this simultaneity rule.
  • Calling starvation a deadlock. Starvation (a process waiting forever while others make progress) involves no ring of mutual blocking — it is a scheduling failure, not a deadlock. The two are often paired in textbooks but are different failure modes.

Exam note: the four necessary conditions — mutual exclusion, hold and wait, no preemption, circular wait — and the rule that all four must hold simultaneously are exactly the kind of statement the examination expects; master the list and the simultaneity wording. Recap + bridge: a deadlock is the simultaneous presence of these four conditions, and removing any one of them removes the deadlock. Next we draw the system as a graph — the resource allocation graph — where the search for deadlock becomes a search for cycles.

9.3 Resource Allocation Graphs

The processes and resources of a system can be pictured with the resource allocation graph (RAG), which makes deadlock questions much easier to see. By drawing the graph and looking for cycles, we can say whether a deadlock exists.

Hook — deadlock detection becomes a drawing exercise. A system with dozens of processes and resources is hard to reason about from tables, but the question "is anyone waiting on a closed ring?" can be answered by drawing one directed graph and running a cycle check on it. This section builds that graph, and the rules at its core — "no cycle means no deadlock" — were marked very, very important in class.

9.3.1 Vertices and Edges: Request Edges and Assignment Edges

The graph has a set of vertices, call it V, and a set of edges, call it E. V consists of two kinds of vertices: every process P1, P2, up to Pn, and every resource type R1 up to Rm present in the system. There are two named edges:

  • A request edge: if process P1 is requesting resource R1, the arrow starts from the process and ends at the resource — process → resource.
  • An assignment edge: if a process has already been assigned (holds) a resource, the arrow goes the reverse way, from the resource to the process — resource → process.

The direction of the arrow is the key difference: a process that is in need of a resource points to the resource; a process that already holds a resource is pointed at by the resource. Every graph in this topic is drawn with only these two kinds of edges.

Formal statement. Let where is the set of all processes and is the set of all resource types. Every edge in is one of two kinds:

  • A request edge : process has requested an instance of resource type and is currently waiting for it.
  • An assignment edge : one instance of resource type has been allocated to process .

Read an edge as a statement about the present: request edges say "wants, right now"; assignment edges say "holds, right now". A request edge is inserted the moment a process asks for the resource, it becomes an assignment edge the instant the request is granted, and the assignment edge is deleted when the process releases the resource.

9.3.2 Drawing Conventions: Circles, Squares, and Dots

The drawing rules are simple. A process is drawn as a circle. A resource is drawn as a square. If a resource has several instances, the instances are shown as dots inside the square; for example, a printer with four instances is drawn with four dots, and the four dots alone are enough to tell you the resource has four instances. A request edge starts from the process circle and ends by touching the border of the resource square. An assignment edge starts from a particular dot (a particular instance) inside the square and ends at the process circle, because the process holds one specific instance of the resource. With four instances, each instance may be allocated to one or another process.

Why the dots matter. The square is the type, the dots are the instances. A request edge points at the square's border because the process does not care which particular instance it gets — any copy of the type will do. An assignment edge, however, must start at one specific dot, because the process holds one specific physical copy. This distinction is what lets the graph tell apart "resource has a free copy" from "resource fully allocated": count the dots and compare with the number of assignment edges leaving the square. If the square has two dots and two assignment edges, no instance is free and the next request for that type must wait.

9.3.3 Worked Example: Three Processes and Four Resources

Worked example — three processes, four resources. Take three processes P1, P2, P3 and four resource types, exactly as in the prescribed book's canonical figure. Resource R1 has a single instance; R2 has two instances; R3 has a single instance (the lecture's passing mention of "two instances" for R3 conflicts with the canonical figure, which the two cycles below match exactly — either way, for P2 to be waiting, all of R3's instances must be allocated); R4 has three instances. The holdings and requests:

  • P1 holds one instance of R2 and requests R1.
  • P2 holds one instance of R1 and one instance of R2, and requests R3.
  • P3 holds the single instance of R3. No process has requested R4 at all, so all three of its instances sit idle; P3 may request R4 at a later stage, or P2 may — we do not know.

The edge set is therefore:

Since R1 has only one instance and it is held by P2, P1 has to wait, so it keeps making its request. Since R3's instance is held by P3, P2 waits as well. The graph shows two request edges and four assignment edges — a picture that will soon form its two cycles.

Now the picture changes: P3 requests a resource — one of the instances of R2 — but that is not possible, because both R2 instances are already allocated (to P1 and to P2). Everything is allocated, so P3 waits. The new request edge joins the graph, and now we ask: does a deadlock exist? We look for a cycle — a way to start at some vertex, follow the arrows, and come back to the same vertex. Following the arrows from P1:

and from P2:

Both paths return to their starting vertex: there are exactly two cycles, one through P1 and one through P2. P1 waits for R1 (held by P2), P2 waits for R3 (held by P3), P3 waits for R2 (held by P1 and P2) — a closed ring of three waiting processes.

Sense-check: count the arrows: every assignment edge in the ring is balanced by a request edge from the next process, and the ring returns to its start. The cycle is real. Whether this cycle means a deadlock depends on the number of instances — the question answered in the next subsection.

9.3.4 Cycles, Deadlock, and the Number of Instances

Some basic facts govern the whole method, and they were marked very, very important:

  1. If the graph contains no cycle, there is no deadlock. The procedure: draw the resources and processes, draw the request and assignment edges, then check for a cycle. No cycle → no deadlock.
  2. If the graph contains a cycle and there is only one instance of each resource type, then the cycle is both a necessary and sufficient condition for the existence of a deadlock. With a single instance per type, a cycle means deadlock, for sure.
  3. If the graph contains a cycle but the resources have multiple instances, then the cycle is a necessary but not sufficient condition. There may be a deadlock, or there may not. Why? Because if one of the processes holding an instance releases it, that instance may then be allocated to a process that had already requested it, and the waiting chain unwinds. The chances are better than not, but we cannot say for sure.

The three rules, one picture each. Rule 1: a graph with no closed arrow-loop cannot trap anyone — some process's request will eventually be granted, so the system moves on. Rule 2: with one instance per type, every process in a cycle waits for a resource held by a process in the same cycle, no free copies exist anywhere, and nothing outside the cycle can help — the cycle is the deadlock, both ways. Rule 3: with several instances per type, a resource outside the cycle (or a spare copy inside it) may free the bottleneck — the cycle may break, so the cycle alone does not prove a deadlock.

The example graph from the previous section has a cycle, and here the number of instances decides the story. P3 is in need of R2, and R2's two instances are currently held by P1 and P2 (the lecture's slip mentioning a process "P4" was a slip indeed — this example defines only three processes, and R2's two instances are allocated to P1 and P2). At some later point P1 or P2 may release its instance, and the freed instance may be allocated to P3; anything can happen once a holder finishes using the resource. Even though a cycle exists, there may be no deadlock. This is why, for multiple instances, we need another method — that is what the banker's algorithm in Section 9.6 is for.

Visual intuition. Picture the two cycles from the worked example as two nested loops of arrows: one loop P1 → R1 → P2 → R3 → P3 → R2 → P1, and inside it the shorter loop P2 → R3 → P3 → R2 → P2. Both loops pass through the pair (R2 → P1 / P2). Since R2 has two instances, one held by each process, the "two loops" share the same bottleneck resource; if either P1 or P2 were to finish and release, both loops would snap open at once. That is why a single release can dissolve a cycle when instances are multiple — and why the same graph with all single-instance resources would be an unrecoverable deadlock.

A note on the canonical figure. The prescribed book labels the very graph built above (after joins) as an actual deadlock, because in that figure every instance is fully allocated and every cycle participant is itself waiting — no release is possible. The class's point, and the exam rule, is the general one: with multiple instances a cycle is necessary but not sufficient, and the verdict must be checked instance by instance. Both statements are consistent: a fully allocated multiple-instance system can be deadlocked; the cycle alone just cannot prove it.

9.3.5 Worked Example: Six Resources and Three Processes

The class worked a second example together. Suppose there are six resources — resource types R1, R2, R3, each with two instances — and three processes, each process needing three resources (one instance of each type).

Q: Show one graph example. Suppose there are six resources and three processes, and each process needs two (or three) resources. How many instances does each resource have? Let me state the holdings: P1 is holding one instance of R1 and one instance of R2; P2 is holding one instance of R3 and one instance of R1; P3 is holding one instance of R2 and one instance of R3. To complete its task, P1 needs one instance of R3, P2 needs one instance of R2, and P3 needs one instance of R1. Now is there any cycle? A: Each of R1, R2, R3 has two instances, so all three resource types have multiple instances. First check for a cycle: even if a cycle exists, with multiple instances the cycle is a necessary condition but not a sufficient condition for a deadlock. You have to arrange the drawing so the cycle is visible. Here there is no cycle from the assignment edges alone, because each process holds two resources and the assignments do not loop: P1 is pointed at by R1 and R2, P2 by R3 and R1, P3 by R2 and R3 — no closed ring yet. Now add the request edges: P2 is in need of R2, and R2 is already allocated to this process and that one, so draw P2 → R2. P3 may be in need of R1, so draw P3 → R1. P1 is in need of R3, which is held by P2 and P3, so draw P1 → R3. Starting from P1: P1 → R3 → P2 (R3 is assigned to P2) → R2 → P1 (R2 is assigned to P1) — the arrows come back to where we started, so a cycle is there, like walking through a maze until you find it. But because we have multiple instances, a deadlock may or may not occur. Even if a cycle has been formed, it may be broken later — some process may release one of the resources, and the cycle opens up. The sufficient condition is not merely the cycle: only with a single instance per resource type does a cycle mean a deadlock for sure. Here the probability of a deadlock is lower, and the single cycle that has formed may be broken at a later stage.

The same example, drawn as a table. Holdings (assignment edges) and requests (request edges) in one view:

Process Holds Requests
P1 one R1, one R2 one R3
P2 one R3, one R1 one R2
P3 one R2, one R3 one R1

Trace the cycle from P1's request: (request), (assignment — P2 holds R3), (request), (assignment — P1 holds R2). The arrows return to P1: a single closed cycle exists. Every resource has two instances, so the cycle is necessary but not sufficient — if any holder finishes, the freed instance breaks the ring. Conclusion: a deadlock may occur, but this graph alone does not prove one.

Sense-check: with one instance per type, this exact ring (each process holding two types and requesting the third) would be a guaranteed deadlock. The only difference here is the spare copies — and that difference is precisely the multiple-instance rule.

Real-world connection: resource allocation graphs are the basis of real deadlock detection tools. Databases and hypervisors track lock ownership as directed edges and run cycle-detection algorithms ( on processes) at intervals — the same "follow the arrows" procedure done by software. The graph is also the natural language for explaining incidents: a database deadlock report that prints "transaction A holds row 5, waits for row 9; transaction B holds row 9, waits for row 5" is a resource allocation graph in text form.

Common pitfalls in this section.

  • Ignoring the arrow direction. Request edges point process → resource; assignment edges point resource → process. Reversing even one arrow changes the cycle verdict entirely — always check "who points at whom" before judging the graph.
  • Declaring deadlock from any cycle. The single most repeated correction of this lecture: a cycle with multiple instances is not proof of a deadlock. Only single-instance cycles are decisive.
  • Forgetting the dots. A request edge touches the square's border; an assignment edge must start from a specific dot. A square with one dot and one assignment edge has no free instance — count dots versus assignment edges before concluding a request can be granted.
  • Skipping the "no cycle" case. Rule 1 cuts both ways and is the most useful check: no cycle at all means no deadlock, full stop — that alone answers many exam questions without touching the banker's algorithm.

Exam note: the cycle rules were repeated as very, very important — no cycle means no deadlock; with a single instance per type a cycle is necessary and sufficient; with multiple instances it is necessary but not sufficient. The "necessary and sufficient" versus "necessary but not sufficient" wording is exactly what the examination asks for. Recap + bridge: the resource allocation graph turns deadlock detection into a cycle search, and the number of instances decides whether a cycle convicts. When instances are multiple, the graph alone cannot decide — next we move from reading pictures to running algorithms: three ways to handle a deadlock, and then the banker's algorithm.

9.4 Three Ways to Handle a Deadlock

9.4.1 Prevention, Detection and Recovery, or Ignoring

Once we understand that deadlocks are possible, we have to decide how to handle them. There are two serious strategies, and a third lazy one. First, prevention: ensure that the system will never enter the deadlock state at all. Second, detection and recovery: allow the system to enter the deadlock state, detect that it has done so, and then recover from it. Third, ignoring: pretend everything is fine and act as if the deadlock never happened — that is the last resort, used by many systems in practice because deadlocks are rare. The aim, stated simply, is to prevent, avoid, detect, or recover.

Hook — three very different budgets. Think of deadlock handling as an insurance decision. Prevention pays a constant premium (resources are under-used, requests are constrained) to guarantee the accident never happens. Detection and recovery pays only after the accident, but the payout is a rollback or a lost transaction. Ignoring pays nothing and hopes the accident is rare — which, on real systems, it often is. The three strategies are a trade between constant cost, crash-and-recover cost, and risk.

The three strategies, precisely.

  • Prevention — guarantee, by design, that the deadlock state is impossible to reach. This is done by making one of the four necessary conditions structurally impossible (Section 9.5 attacks each condition in turn). The system never enters the deadlock state because it cannot.
  • Detection and recovery — let the system run freely, watch for the deadlock state (for example, with the cycle checks of Section 9.3 or a wait-for analysis), and when one is found, break it: abort one of the deadlocked processes, or preempt a resource from it and give the resource to the others.
  • Ignoring — the classic "ostrich algorithm": act as if deadlocks never happen. This is not laziness for its own sake: many operating systems — including mainstream UNIX and Windows families — take this route, because their deadlocks are rare and the constant cost of prevention or avoidance is higher than the rare cost of a manual restart. The burden then shifts to the application developer, who must write programs that avoid or tolerate deadlocks.

The professor's summary line: the aim is to prevent, avoid, detect, or recover. Notice that "avoid" sits between prevent and detect: avoidance does not make the deadlock impossible (like prevention), it keeps the system out of the states where a deadlock can arise (unlike detection, which waits for the damage).

9.4.2 Prevention versus Avoidance

Prevention and avoidance are different approaches, and the difference is the information each one needs. Prevention works by making sure that at least one of the four necessary conditions can never hold. If one of the four conditions — mutual exclusion, hold and wait, no preemption, circular wait — cannot occur, then the deadlock has been prevented. Prevention needs no a priori information: the system never needs to know in advance how many resources each process will use overall.

Avoidance has a different goal: keep the system in a safe state and make sure it never enters an unsafe state, so that it never reaches the deadlock state. For this, the system needs additional a priori information about the overall use of each resource by each process. Each process must declare, up front, things like: P1 needs three instances of R1, two instances of R2, and one instance of R3. Only with that declared information can the system decide whether granting a request is safe. What a safe state and an unsafe state are is explained in Section 9.6.

Prevention versus avoidance, side by side. The lecture drew the contrast on the one dimension that really separates them — what the system must know in advance:

Deadlock Prevention Deadlock Avoidance
Goal Make one of the four conditions impossible, so deadlock cannot occur Keep the system in a safe state, so deadlock never occurs even though it is possible
Information needed None — no advance knowledge of resource usage A priori declarations — each process states its maximum need for every resource type
Mechanism Constrain how requests are made (protocols) At every request, simulate the allocation and check safety before granting
Example tools Resource ordering, all-resources-up-front (Section 9.5) Claim edges, banker's algorithm (Section 9.6)
Typical cost Low resource utilization, possible starvation Extra bookkeeping and per-request simulation

The professor's phrasing to remember: prevention breaks one of the four conditions; avoidance keeps the system out of unsafe states. When to pick which: prevention when the resource set is small and stable (it can be applied without any process cooperation on declarations), avoidance when the system can afford to demand that each process declare its maximum need — which many real applications cannot truthfully guarantee.

Real-world connection: database engines combine the strategies. MySQL InnoDB and Oracle run in detection-and-recovery mode: they allow lock waits, detect the cycle, and roll back the smallest transaction in it — a real "recover from the deadlock" implementation. Systems that cannot tolerate rollback (some real-time controllers) instead forbid the conditions by construction. And the "ignoring" strategy is everywhere: everyday desktop and server operating systems ship without deadlock avoidance, betting on rarity — which is why database transactions were invented to bring the safety guarantee back at the application layer.

Common pitfalls in this section.

  • Using "prevention" and "avoidance" as synonyms. They are different strategies with different information requirements: prevention needs no advance knowledge and works by breaking a condition; avoidance needs declared maximums and works by refusing unsafe allocations. The exam distinguishes them, so should you.
  • Thinking ignoring means "no code runs". Ignoring does not remove the deadlock risk — it pushes it to application developers, who must use timeouts, lock ordering, or transactions to survive.
  • Assuming detection is free. Detection-and-recovery pays a price: the detection scans themselves cost time, and recovery (aborting processes, rolling back transactions) can destroy work done since the deadlock formed.

Recap + bridge. There are three ways to handle a deadlock: prevent it (make it impossible), detect it and recover, or ignore it — and prevention and avoidance differ in the a priori information they need. Next we examine prevention in detail: how each of the four conditions can be attacked, and what the attack costs.

9.5 Deadlock Prevention: Break One of the Four Conditions

The aim of prevention is to make at least one of the four necessary conditions never occur. We go through the conditions one by one and see how each can be attacked.

Hook — you only need to break one link. The four necessary conditions are four links of one chain: a deadlock forms only when all four hold at the same time. Prevention therefore has a wonderfully cheap goal — demolish any single link and the chain can never close. This section attacks each link in turn, and the honest price of each attack shows up at the end: resources sit unused, and some processes starve.

9.5.1 Mutual Exclusion Cannot Be Prevented for Non-Shareable Resources

For mutual exclusion, we first separate shareable resources from non-shareable resources. A non-shareable resource, such as a printer, can be used by only one process at a time; a read-only file is a shareable resource, usable by many readers at once. If a resource is shareable, mutual exclusion is not required for it — but then it is not the source of a deadlock either, because no one waits for it. We are always dealing with non-shareable resources when deadlocks matter. If a non-shareable resource has a single instance, then mutual exclusion definitely happens — the resource cannot be shared. So we cannot prevent a deadlock by attacking mutual exclusion for non-shareable resources; we must check whether the next condition can be prevented instead.

Why this condition is immune to prevention. To break mutual exclusion we would have to make every resource shareable — but a printer cannot print two documents at once and a DVD drive cannot serve two readers at once; these resources are intrinsically non-shareable. The professor's test: ask "can several processes use it at the same time without corrupting anything?" A read-only file passes the test (all readers see the same bytes), so it is shareable and can never be in a deadlock. A printer fails the test, so mutual exclusion holds for it no matter what policy we invent — and the first link of the chain survives every attack. The conclusion is structural: for non-shareable resources, mutual exclusion is not preventable, so prevention must be aimed at hold and wait, no preemption, or circular wait instead.

9.5.2 Breaking Hold and Wait: Two Protocols

To make hold and wait impossible, we guarantee that whenever a process requests a resource, it does not hold any other resource. If P1 needs R1, it should not also hold R2 or R3 — there must be no assignment edge from those resources to P1 while it is requesting R1. Two protocols achieve this:

  • Protocol 1 — request everything up front: a process requests and is allocated all the resources it will ever need before it starts execution. There is no partial allocation: if P1 needs R1, R2, and R3, all three are given at once, P1 uses everything, and only after P1 releases them does P2 receive whatever it needs.
  • Protocol 2 — request only when holding nothing: a process may request a resource only when it holds no other resource. If P1 wants R1, it must first release every resource it already holds, and only then ask for R1. So a process uses a resource, releases it, and then requests the next one.

One caution: if resource utilization is very low, there is a possibility of starvation. Suppose only R1 is in demand and no process ever requests R2, even though R2 exists and is free — utilization of R2 is zero, every process fights over R1, and some processes may wait forever. The requests should be balanced so every process requests and acquires each of the resources it needs.

Worked example — the DVD, the file, and the printer. Consider a process that must copy data from a DVD drive to a disk file, and then print the file. Under the two protocols:

  • Protocol 1 (all up front): the process requests the DVD drive, the disk file, and the printer at the very start. It then sits holding the printer for the whole job even though it only needs the printer at the end — the printer is blocked from every other process for the entire run. Resource utilization is low, but no request can ever wait for a held resource, so hold and wait cannot occur.
  • Protocol 2 (release before next request): the process requests the DVD drive and the disk file, copies, then releases both. Now it requests the disk file and the printer, prints, and releases both. No moment exists at which it holds one resource while asking for another — hold and wait cannot occur either.

Both protocols eliminate hold and wait; the difference is timing. Protocol 1 is simpler but wastes resources for long stretches; Protocol 2 uses resources more tightly but forces the process to release and re-request, which only works if the data survives on the disk in between (it does here — that is the point of copying to the file first).

Sense-check: in both traces, at every request moment the process holds zero resources. The condition "requests only when holding nothing" holds by construction — hold and wait is dead, and with it the second link of the chain.

9.5.3 Breaking No Preemption: Two Protocols

"No preemption" means a process keeps using a resource without interruption; to prevent deadlock we want preemption to be possible. Two protocols:

  • Protocol 1 — release everything if you cannot get the next resource: if a process holding some resources requests another resource that cannot be allocated immediately, then all the resources currently held by the process are released. Example: P1 holds R1 and R2 and requests R3; if R3 is not immediately available, P1 first releases R1 and R2. The preempted resources are added to the list of resources needed by the process (they are still required later). The process is then restarted — because it had not finished using the resources before they were preempted — and after some time it must regain all the resources it used before, plus the one it was requesting.
  • Protocol 2 — preempt from a waiting process: if a process requests a resource, we check whether an instance is free. Suppose P1 asks for R1, but R1 is held by P2, and P2 is itself waiting for some other resource, say R3. Then we preempt the desired resource (R1) from the waiting process P2 and allocate it to P1. That way preemption happens without stopping a process that is actually working.

What makes this practical — and what doesn't. Protocol 1 turns every blocked request into a full release-and-restart, so no process ever waits while holding; Protocol 2 takes resources only from processes that are themselves waiting, so a working process is never disturbed. Both protocols work well only when the preempted resource's state can be saved and restored later — CPU registers and memory space qualify (their contents can be written out and reloaded). They cannot be applied to printers or tape drives: a half-printed document cannot be "saved" and resumed. This is why the no-preemption link is attacked in practice only for stateful, saveable resources, and why the next condition is the preferred target.

9.5.4 Breaking Circular Wait: Ordering Resource Types

To prevent circular wait, impose a total ordering on all resource types and make every process request resources in increasing order of enumeration. Assign each resource type a number through a function F, and require that a process never requests a resource with a number lower than (or equal to) one it already holds. If R1 gets the number 2 and R2 gets the number 5, the request order must go 2 → 5, increasing, never the reverse.

The ordering rule, formalized. Define a one-to-one function that assigns every resource type a distinct natural number — a "rank". The rule: a process may request an instance of type only if for every type it already holds; if several instances of the same type are needed, they must be requested together in one single request. Equivalently: a process must release any resource with rank the rank of the resource it wants before asking for it. Because the rank numbers strictly increase along every process's request sequence, and a circle would force the numbers to both increase and come back down, no circular wait can form.

Example: three resources — a DVD, a file, and a printer. Suppose P1 needs the DVD and the file, and then a printer to send information to print. We assign numbers in increasing order: DVD gets 2, the file gets 4, and the printer gets the next number. Then P1 must first ask for the DVD, then for the file, and only then for the printer — it may never ask for the file first and the DVD second, and all three should not be held by P1 at the same time. The resource that is already allocated must have a number less than the number of the resource being requested.

Why does this rule kill circular wait? Suppose a circular wait existed. The process holding R1 would be waiting for a resource with a higher number, say R2; holding R2 would wait for R3, and so on, giving . Going around the circle we end back at R1, which would require — but the numbers cannot both be increasing and come back down. The ordering makes the circle impossible; the contradiction proves there is no circular wait.

The contradiction means the assumed circular wait cannot exist: with a consistent total ordering, the ring of arrows can never close. In the small example: DVD (2) → file (4) → printer (6) is the only legal direction, so a "waiting ring" would need someone to go from printer (6) back to DVD (2) — forbidden by the rule.

The main problem with this scheme is low device utilization: the printer may not be used for a long time, device utilization falls, and overall system throughput decreases. These costs are the price of prevention.

9.5.5 The Price of Prevention: Low Utilization and Starvation

To summarize the cost side: breaking hold and wait by allocating everything up front wastes resources, because a process may hold resources it will not use for a long time; low utilization can cause starvation, as in the R1-only example; breaking circular wait by ordering can leave some device idle for long stretches; throughput drops. These are the trade-offs, but if we must prevent a deadlock, then at least one of the four conditions must be made impossible — no mutual exclusion, or no hold and wait, or preemption, or no circular wait.

Real-world connection: resource ordering is exactly what real systems use. Database engines teach transactions to acquire locks in a fixed order (for example, always lock account A before account B) to make lock-wait rings impossible, and tools like FreeBSD's witness monitor running kernels, recording the order in which mutexes are acquired and warning on the console the moment a thread violates the ordering. The price is familiar to every database administrator: transactions hold locks longer, contention rises, and throughput falls — the same utilization-versus-safety trade the professor describes.

Common pitfalls in this section.

  • Believing mutual exclusion is preventable. It is not, for non-shareable resources — a printer cannot be shared. Prevention attacks the other three conditions; mutual exclusion is attacked only by changing the resource (making it shareable), which is usually impossible.
  • Forgetting the "or equal to" ban. The rule says a process may never request a resource with rank lower than or equal to the highest rank it holds. Requesting two instances of the same type must be a single request — splitting it re-opens the door to circular wait.
  • Ignoring starvation as a prevention side effect. Prevention removes deadlock but can introduce starvation: when one resource type is in heavy demand, some processes may wait forever for it. Balanced requests are the countermeasure.
  • Applying preemption to the wrong resources. Preempting a printer mid-job destroys the job; preemption protocols are practical only for resources whose state can be saved and restored (registers, memory).

Recap + bridge. Prevention makes at least one of the four conditions impossible: mutual exclusion cannot be prevented for non-shareable resources, hold and wait yields to two request protocols, no preemption yields to two preemption protocols, and circular wait dies under a total resource ordering — all at the price of low utilization and possible starvation. Prevention asks nothing of processes in advance; the next strategy, avoidance, asks everything: it demands that every process declare its maximum need up front, and then keeps the system in safe states — the banker's algorithm territory of Section 9.6.

9.6 Deadlock Avoidance

9.6.1 A Priori Information and the Resource Allocation State

If the operating system is given complete information about each process — how much it has requested and how much it will release — then a deadlock can be avoided. This sounds simple and useful, but there is a catch: we would need to know the future requests and releases of each resource. When P1 needs R1 we do not know at present — it may be holding R2 right now, and it may need R1 or R3 later. Those future needs cannot be predicted in general. What we do know is captured in the resource allocation state: the number of available resources, how many instances have been allocated to each process, and the maximum demand of each process.

Hook — the bank that never goes bust. Imagine a bank that lends money to customers, each of whom has a credit limit and repays only after borrowing the full limit. The bank cannot know exactly when a customer will ask for more money, but it can decide, before every loan, whether granting it could leave the bank unable to satisfy every customer's remaining credit. If the bank only ever makes loans that keep this guarantee true, it can never go broke. Deadlock avoidance is this banking policy applied to resources: every process declares its maximum demand up front, and the operating system refuses any allocation that could lead to a state from which some process can no longer finish.

Avoidance needs a priori information. The defining difference from prevention (Section 9.4): avoidance needs the system to know, before a process starts, the maximum number of instances of each resource type the process may ever request. This a priori declaration turns "maybe a deadlock later" into a decision the system can make today: each request is granted only if the resulting state is still safe. Prevention never needs this — it just bans a condition. Avoidance uses the declared maximums to keep the system inside the safe region of states forever, so the deadlock state is never even approached.

The resource allocation state is the complete picture the system reasons with: (1) how many instances of each resource type are currently available, (2) how many instances of each type are currently allocated to each process, and (3) the maximum demand each process declared. Every request, grant, and release moves the system from one state to the next; avoidance is the policy of only ever moving to safe states.

9.6.2 Safe States and Unsafe States

A state is safe if there exists a sequence of processes such that there are enough resources for the first process to finish, and as each process finishes and releases its resources, there are enough for the next one to finish. If we write some sequence P1, P2, P3 — any sequence, not necessarily the order of creation — then P1 finishes first, releases its resources, P2 gets what it needs and finishes, and so on to P3. More carefully: if a process Pi needs a resource that is not immediately available, Pi has to wait until some Pj completes; when Pj completes, Pi can take the needed resource, execute, return the allocated resource, and terminate; then Pi+1 can obtain the resource, and the sequence goes on.

From this comes the central link: if a system is in a safe state there is no deadlock. If a system is in an unsafe state there is a possibility of deadlock. Avoidance means ensuring the system never enters an unsafe state; then the deadlock is avoided. Two statements to keep straight, and they are easy to confuse:

  • All deadlocks are unsafe states.
  • Not all unsafe states are deadlocks.

Picture the whole space of states: inside it there is a safe region where no deadlock can occur; outside the safe region lies the unsafe region, where a deadlock is possible but not certain; and inside the unsafe region there is a smaller portion that actually is the deadlocked state. A deadlock, when it occurs, is always within the unsafe region — but being unsafe does not mean being deadlocked.

Safe state, formalized. A state is safe if there exists a safe sequence: an ordering of the processes such that, for each , the additional resources can still request are satisfied by the currently available resources plus the resources held by all processes that already finished. If the resources needs are not immediately available, waits until the earlier processes finish; when they do, obtains everything it needs, runs, returns its allocation, and the next process proceeds. If no such ordering exists, the state is unsafe. Three claims follow, and each is worth an exam sentence:

  • A safe state is never deadlocked — there is at least one guaranteed path to completion.
  • Every deadlocked state is unsafe — in a deadlock no process can finish, so no ordering can work.
  • Not every unsafe state is deadlocked — an unsafe state may lead to a deadlock if the wrong request is granted next, but the processes might also make requests that keep things moving.

Worked example — twelve tape drives. This is the standard illustration of safe versus unsafe. A system has twelve tape drives and three processes: P0 may need up to ten drives, P1 up to four, P2 up to nine. At time t0, P0 holds five drives, P1 holds two, P2 holds two; three drives remain free.

Is the state safe? Try the sequence :

  1. P1 needs 4 − 2 = 2 more drives; 2 ≤ 3 free, so P1 gets them, runs, and returns all four: free = 3 − 2 + 4 = 5.
  2. P0 needs 10 − 5 = 5 more drives; 5 ≤ 5 free, so P0 runs and returns all ten: free = 5 − 5 + 10 = 10.
  3. P2 needs 9 − 2 = 7 more drives; 7 ≤ 10 free, so P2 runs. All three processes complete.

The state at t0 is safe, with safe sequence . Now suppose, at time t1, P2 is granted one more drive (free drops from 3 to 2). Recheck: P1 needs 2 more (2 ≤ 2 — P1 can still run and return four drives, free = 2 − 2 + 4 = 4). But now P0 needs 5 more and only 4 are free — P0 must wait; P2 may request 6 more and wait too. The state at t1 is unsafe: the wrong next request could produce a deadlock. The mistake was granting P2 that drive; had P2 waited, the system would have stayed safe.

Sense-check: in the safe state a complete ordering exists; in the unsafe state no ordering covers all three processes. One grant flipped the system from safe to unsafe — that is exactly what avoidance must prevent at every single request.

9.6.3 Single-Instance Systems: The Claim Edge

For a system where each resource type has a single instance, avoidance uses the resource allocation graph with one extra kind of edge. Alongside the request edge and the assignment edge, there is a third edge called the claim edge. A claim edge indicates that the process may request this particular resource at some point in the future. It is drawn as a dashed line from the process to the resource (the other edges are solid, and the assignment arrow points the reverse way). The life cycle of an edge:

  • A claim edge may be converted into a request edge when the process actually requests the resource — but we do not know when that will happen.
  • A request edge is converted into an assignment edge when the resource is allocated.
  • When the resource is released, the assignment edge is converted back into a claim edge, because after some time the same process may use the resource again.

All claim edges must be declared a priori — mentioned before the process starts. Consider a graph where R1 is assigned to P1, and P1 may need R2 in the future (dashed claim edge P1 → R2). P2 is requesting R1, which is held by P1, and P2 may also claim R2. If, later, P1's claim converts to a request and P1 is allocated R2, there is no cycle. But if P2's claim converts to a request and the resource is allocated to P2, the request edge creates a cycle, and a deadlock may follow. In a single-instance system, seeing the cycle tells us a deadlock may occur — the claim is not yet a request, so the cycle is only possible, but the moment the claim becomes a request the deadlock risk is real.

The claim-edge algorithm. In a single-instance system, each process declares all the resources it may ever want by drawing dashed claim edges before it starts. When process actually requests , the request can be granted only if converting the request edge into an assignment edge does not create a cycle in the graph. If it would create a cycle, the allocation would move the system into an unsafe state, so must wait. Since every resource type has a single instance, a cycle here is decisive: in a single-instance system a cycle means a deadlock is unavoidable once the corresponding requests are made. Detecting the cycle is cheap — a cycle check on a graph with process vertices costs on the order of operations, and no simulation of future behavior is needed. This is the whole reason the graph method suffices for single-instance systems, and the reason it fails for multiple instances: with several instances, a cycle is not proof, so we need the heavier machinery of the banker's algorithm.

9.6.4 Multiple-Instance Systems: The Banker's Algorithm

When resource types have multiple instances, the graph method is not enough, and we use the banker's algorithm. The algorithm handles multiple instances, and while it was not claimed to be very powerful, it does help to avoid a deadlock.

The assumptions behind it: every process has to claim the maximum use of each and every resource; a process has to request a resource, and sometimes it may need to wait; only when a process gets all its resources will it return them, and it must return them within a finite amount of time — if it acquires a resource at time t1, then at t2 or t3 it has to give it back after completing its work; it cannot hold a resource for a longer time.

Where the name comes from. The algorithm is due to Edsger Dijkstra (1965) — the "banker" of the name is not a person who discovered it but the banking analogy that inspired it. Just as a bank lends money only when it can still satisfy every customer's credit limit, the algorithm grants resources only when every process can still reach its maximum and finish. The mapping: customers are processes, their credit lines are the declared maximums, loans are allocations, and the bank's cash reserve is the pool of available instances. The name stuck because the guarantee is the same — never lend so much that a customer's full credit line cannot be honored later. The assumptions above are exactly the banking rules restated: declare a credit line, borrow piece by piece, and always repay within a finite time.

9.6.5 The Four Data Structures

Let n be the number of processes and m the number of resource types. The algorithm needs four data structures:

  • Available: a vector of length m. means there are k instances of resource type Rj currently available. For example, if we call the printer resource type one, then says three printer instances are free right now.
  • Max: an n × m matrix. means process Pi may request at most k instances of resource type Rj over its whole life.
  • Allocation: an n × m matrix. means process Pi is currently allocated k instances of Rj.
  • Need: an n × m matrix. means process Pi may need k more instances of Rj to complete its task.

The need of a process is what is left after what it already has. The formula — stated in class as one to remember and use:

Reading the four structures. Think of each process as a row and each resource type as a column. The matrices Max, Allocation, and Need all have the same shape: rows (one per process) and columns (one per resource type). Available is a single row of length . The relation between rows: for every process and every resource type , the declared maximum is the sum of what is already given and what may still be needed — so the Need formula above always holds by definition. The comparison between two vectors means for every component ; rows of Allocation and Need are treated as vectors (Allocation, Need) when we ask "can still be satisfied?"

9.6.6 The Safety Algorithm

The safety algorithm decides whether the current state is safe. It uses two more variables, each a vector: Work of length m and Finish of length n.

  1. Initialize: and for every process . Setting Finish to false means: as of now, no process has completed its task.
  2. Find an index i such that and the need satisfies for every resource type j. If no such i exists, go to step 4.
  3. Assume the process finishes: for all j (the process is allocated what it needs, does its work, and returns everything, so the pool grows), set , and go back to step 2.
  4. If for all i, the system is in a safe state; otherwise the system is unsafe. The loop continues until no other process can be satisfied, and only then do we declare the outcome.

The safety rule in one equation. A process can be added to the safe sequence when its remaining need fits inside the current work pool, and finishing it grows the pool by its entire allocation:

The algorithm is a greedy simulation: repeatedly find any unfinished process whose remaining need fits in the current pool, mark it finished, and add its allocation back to the pool. If the loop can mark every process finished, a safe sequence exists (the order in which they were marked) and the state is safe. If it stalls with processes still unfinished, the state is unsafe. The cost: determining safety takes on the order of operations ( scans of up to processes, each comparing components), which is why the banker's algorithm is called "not very powerful" in the lecture — it is correct but expensive, and it must be re-run on every request.

9.6.7 Worked Example: Five Processes and Three Resource Types

The banker's algorithm in class — five processes, three resource types. The system has ten instances of type A, five of type B, and seven of type C. At time T0 the snapshot is:

Process Allocation (A B C) Max (A B C) Need (A B C)
P0 0 1 0 7 5 3 7 4 3
P1 2 0 0 3 2 2 1 2 2
P2 3 0 2 9 0 2 6 0 0
P3 2 1 1 2 2 2 0 1 1
P4 0 0 2 4 3 3 4 3 1

The Need column is computed with the formula: Max minus Allocation. Check a couple of rows: for P0, 7 − 0 = 7, 5 − 1 = 4, 3 − 0 = 3, so Need is 7 4 3; for P1, 3 − 2 = 1, 2 − 0 = 2, 2 − 0 = 2, so Need is 1 2 2. The other rows work the same way. The Available vector at time T0 is 3 3 2 (check: total 10 5 7 minus the allocation column sums 7 2 5 gives 3 3 2).

The game is to find a safe sequence — the order in which to execute the processes so that each process takes its needed resources, completes its work, returns the resources, and the next process can then proceed. The sequence is not necessarily P0, P1, P2, P3; it may be a different order. The sequence found in class is P1, P3, P4, P0, P2. It is not the only safe sequence — you can pick another order and prove it also leads to a safe state (the prescribed book's own sequence for this snapshot is P1, P3, P4, P2, P0, which also works); this is just one of the safe states. The walkthrough, step by step:

  • P1 first: Need P1 = 1 2 2 against Work = Available = 3 3 2. Since 1 ≤ 3, 2 ≤ 3, 2 ≤ 2, the condition holds. Grant the need: the pool drops to 3 3 2 − 1 2 2 = 2 1 0. P1 now holds its full maximum 3 2 2 (its allocation was 2 0 0; with the granted 1 2 2 it holds 3 2 2), finishes, and returns everything: Work = 2 1 0 + 3 2 2 = 5 3 2. Finish[P1] = true.
  • P3 next: Need P3 = 0 1 1 ≤ Work 5 3 2. Grant: 5 3 2 − 0 1 1 = 5 2 1. P3 reaches its maximum 2 2 2, finishes, returns: Work = 5 2 1 + 2 2 2 = 7 4 3. Finish[P3] = true.
  • P4 next: Need P4 = 4 3 1 ≤ Work 7 4 3. Grant: 7 4 3 − 4 3 1 = 3 1 2. P4 reaches its maximum 4 3 3, finishes, returns: Work = 3 1 2 + 4 3 3 = 7 4 5. Finish[P4] = true.
  • P0 next: Need P0 = 7 4 3 ≤ Work 7 4 5. Grant: 7 4 5 − 7 4 3 = 0 0 2. P0 reaches its maximum 7 5 3, finishes, returns: Work = 0 0 2 + 7 5 3 = 7 5 5. Finish[P0] = true.
  • P2 last: Need P2 = 6 0 0 ≤ Work 7 5 5. Grant: 7 5 5 − 6 0 0 = 1 5 5. P2 reaches its maximum 9 0 2, finishes, returns: Work = 1 5 5 + 9 0 2 = 10 5 7. Finish[P2] = true.

Every Finish value is true, so the state is safe, and following this safe sequence means no deadlock — the deadlock has been avoided. Sense-check: the final pool 10 5 7 equals the total instances in the system (10 A, 5 B, 7 C) — every resource has been returned, which is exactly what must happen when all five processes complete.

The subtraction-versus-addition confusion, flagged in class. While a process is running, its granted resources are subtracted from the available pool, so the pool shrinks; but when the process completes, the maximum it used is added back, so the pool grows. You should not get confused between the subtraction during allocation and the addition on completion — both appear in each step above. In the walkthrough, "Grant: 5 3 2 − 0 1 1 = 5 2 1" is the subtraction (the pool shrinks while P3 works), and "returns: 5 2 1 + 2 2 2 = 7 4 3" is the addition (the pool grows when P3 finishes). Equivalently, the safety algorithm writes the net effect as Work = Work + Allocation[P3] = 5 3 2 + 2 1 1 = 7 4 3 — one step instead of two, same result.

9.6.8 The Resource-Request Algorithm

Any process may request any resource at any time, and the system must decide whether the request can be granted. The request is recorded in a fifth data structure: means process Pi wants k more instances of resource type Rj. The resource-request algorithm checks the request in steps:

  1. Check against Need: if (component by component), go to step 2; otherwise raise an error — the process has exceeded its maximum claim. A process may request only up to its declared need.
  2. Check against Available: if , go to step 3; otherwise the process must wait until the resource is available.
  3. Pretend to allocate: modify the state as if the request were granted:

Then run the safety algorithm on this pretend state. If the pretend state is safe, the request is granted for real. If it is unsafe, the process waits, and the older resource-allocation state is restored.

Why "pretend" first? The three modified quantities are exactly the changes a real grant would make: the free pool loses the granted instances, the process's allocation gains them, and its remaining need shrinks by the same amount. The system then asks the safety algorithm the one question that matters: after this grant, can every process still finish? If yes, the grant is made for real; if no, the system rolls back to the pre-request state and the process waits. Notice the two-step filtering: step 1 blocks requests beyond the declared maximum (an error, not a wait), step 2 blocks requests the pool cannot cover (a wait), and step 3 blocks requests that would make the state unsafe (a wait, with the old state restored). If the request cannot be granted and the process waits, the system may be in an unsafe state — but that does not mean it is deadlocked; unsafe is only the possibility of a deadlock, as Section 9.6.2 explained.

9.6.9 Checking a Request: 1 0 2 by P1

Request (1 0 2) by P1 — worked in full. Back in the worked example's state (Available 3 3 2, Need P1 = 1 2 2, Allocation P1 = 2 0 0), suppose P1 requests the additional resource amounts 1 0 2. Run the request checks:

  • Step 1 — against Need: is 1 0 2 ≤ Need P1 = 1 2 2? Yes — 1 ≤ 1, 0 ≤ 2, 2 ≤ 2 — so the request stays within P1's maximum claim. (If a process ever requested more than its need, the error "process has exceeded its maximum claim" is raised.)
  • Step 2 — against Available: is 1 0 2 ≤ Available 3 3 2? Yes — 1 ≤ 3, 0 ≤ 3, 2 ≤ 2 — so we go to step 3 and pretend to grant it. (If the request had been larger than the available, the process would have to wait.)
  • Step 3 — pretend the allocation: Available becomes 3 3 2 − 1 0 2 = 2 3 0; Allocation[P1] becomes 2 0 0 + 1 0 2 = 3 0 2; Need[P1] becomes 1 2 2 − 1 0 2 = 0 2 0. The safety algorithm is then run on this pretend state: Work = 2 3 0; P1 fits (0 2 0 ≤ 2 3 0) so Work = 2 3 0 + 3 0 2 = 5 3 2; then P3 (0 1 1 ≤ 5 3 2) gives Work = 7 4 3; P4 (4 3 1 ≤ 7 4 3) gives Work = 7 4 5; P0 (7 4 3 ≤ 7 4 5) gives Work = 7 5 5; P2 (6 0 0 ≤ 7 5 5) gives Work = 10 5 7. Every Finish becomes true, so the pretend state is safe.

The request is granted. P1's allocation becomes 3 0 2 and the system moves to the new state with Available 2 3 0 — and this new state is safe, exactly as the prescribed book confirms for the same request.

Sense-check: the safety trace on the pretend state is the same shape as the original walkthrough (P1, P3, P4, P0, P2) and ends at the full pool 10 5 7. Because the pretend state is safe, granting now can never lead to a deadlock — the avoidance guarantee.

The general idea was summarized in class: if we can allocate the resource to a process and the system stays safe, we say the system is safe; if the process waits with the older state restored, the system may be in an unsafe state — but again, unsafe does not mean deadlock.

9.6.10 Practice Problem: Requests by P4 and P0

As practice for the same rules, check whether a request by P4 and a request by P0 can be granted in the worked example's state. Apply the resource-request algorithm: check each request against the process's Need, check against Available, and run the safety algorithm on the pretend state. The example and this practice set will be continued in the next session, along with another example drawn from the exercises. Here is the method applied now, so the checks are ready:

  • P4 requests (3 3 0). Step 1: 3 3 0 ≤ Need P4 = 4 3 1 — yes. Step 2: 3 3 0 ≤ Available 3 3 2 — yes (3 ≤ 3, 3 ≤ 3, 0 ≤ 2). Step 3: pretend — Available becomes 0 0 2, Allocation[P4] becomes 3 3 2, Need[P4] becomes 1 0 1. Run safety on this pretend state with Work = 0 0 2: no process fits — P1 needs 1 2 2, P2 needs 6 0 0, P3 needs 0 1 1, P4 needs 1 0 1, P0 needs 7 4 3 — none are component-wise ≤ 0 0 2. The pretend state is unsafe, so P4's request is denied: P4 waits and the old state is restored.
  • P0 requests (0 2 0). Step 1: 0 2 0 ≤ Need P0 = 7 4 3 — yes. Step 2: 0 2 0 ≤ Available 3 3 2 — yes. Step 3: pretend — Available becomes 3 1 2, Allocation[P0] becomes 0 3 0, Need[P0] becomes 7 2 3. Run safety with Work = 3 1 2: P3 fits (0 1 1 ≤ 3 1 2) → Work = 3 1 2 + 2 1 1 = 5 2 3; P1 fits (1 2 2 ≤ 5 2 3) → Work = 7 2 3; P2 fits (6 0 0 ≤ 7 2 3) → Work = 10 2 5; P0 fits (7 2 3 ≤ 10 2 5) → Work = 10 5 5; P4 fits (4 3 1 ≤ 10 5 5) → Work = 10 5 7. All finish, so the pretend state is safe, and P0's request is granted.

A useful cross-check from the prescribed book: the same two requests, evaluated in the state that results after P1's request (1 0 2) is granted (Available 2 3 0), reach different verdicts — P4's (3 3 0) is refused because the resources are not available, and P0's (0 2 0) is refused because that pretend state is unsafe. The verdict depends on the state the system is in, which is why every request must be re-checked against the current Available, Allocation, and Need.

Real-world connection: avoidance is the philosophy behind resource managers that must never lose a job — batch schedulers, mainframe resource managers, and database deadlock avoidance layers all declare maximums or run pretend-state checks. The banker's algorithm itself is rarely the scheduler of a general-purpose operating system today (real processes cannot truthfully declare future maximums, and the safety scan on every request is costly), but its safe-state idea survives everywhere: "never make a change you cannot complete" is the same guarantee behind two-phase locking in databases and behind transaction managers that refuse to commit a state that cannot be rolled forward.

Common pitfalls in this section.

  • Equating "unsafe" with "deadlock". They are different: all deadlocks are unsafe states, but not all unsafe states are deadlocks. Denying a request because the pretend state is unsafe is normal avoidance behavior — the system is still alive, just careful.
  • Forgetting the Need check. A request that exceeds Need is an error ("exceeded its maximum claim"), not a wait — the process broke its declared contract. A request that exceeds Available is a wait. The two failures have different meanings.
  • Mixing subtraction and addition. While a process runs, its grant is subtracted from the pool; when it finishes, its full maximum is added back. The safety step Work = Work + Allocation merges both — using only one half of the story produces wrong pools.
  • Applying the graph method to multiple instances. Claim edges decide single-instance systems; with multiple instances a cycle is not decisive and only the banker's algorithm's safety scan can rule. Reaching for the graph where the banker's algorithm belongs is a classic exam mistake.
  • Treating Need as the maximum. Need is the remaining demand (Max minus Allocation); Max is the lifetime ceiling. P0's Need 7 4 3 is not "P0 wants 7 4 3 total" — it is what P0 still needs on top of its allocation 0 1 0.

Exam note: the course plan places this module's first half — up through deadlock avoidance — before the mid-semester examination. The professor's guidance is explicit: the four necessary conditions and their simultaneity rule, the cycle rules for resource allocation graphs, and the formula Need = Max − Allocation are the statements to master; the banker's algorithm worked example was stated as not part of the mid-semester ("no need to worry" for now), though it belongs to the full comprehensive topic set. Recap + bridge: avoidance demands a priori maximum declarations, keeps the system in safe states via the safety algorithm, and grants each request only when the pretend state stays safe — the banker's algorithm for multiple instances, claim edges for single instances. With prevention and avoidance covered, the remaining half of the module — detection and recovery — takes the opposite posture: let the deadlock happen, find it, and break it.

Exam Guidance Summary

Exam note: the coverage plan for the course is that up to module 4 the topics are process synchronization, and this session starts the next module, deadlocks. The plan is to cover the first half of the deadlock module — up through deadlock avoidance — before the mid-semester examination, and the remaining topics after the mid-semester. For the comprehensive exam, all topics are included. The banker's algorithm worked example was explicitly stated as not being part of the mid-semester, so it can be set aside for the mid-semester — "no need to worry" — but it does belong to the full topic set.

Exam note: for process scheduling problems, answers may be typed or written by hand and scanned/uploaded — both facilities are available, and for scheduling you have to solve the problems regardless: draw the table and the Gantt chart, work the computation in the notebook, and submit. For whichever question, choose whichever method is feasible for that particular question. The prescribed book is the book to follow, and the class example for the banker's algorithm is even in the book; the next session takes another example from the exercises at the end of the chapter.

Exam note: the four necessary conditions and their simultaneity rule are the kind of statement to expect — "you can master" it, and the "necessary and sufficient" versus "necessary but not sufficient" distinction for cycles in a resource allocation graph was repeated as very, very important. The formula Need = Max − Allocation was also emphasized as one to remember and use.

Exam note: the mid-semester examination is next week, with a makeup examination on the last day of the makeup period; the advice is to concentrate on the examination — all the best.

How to study for this module's first half. Four skills, in the order the lecture built them: (1) recite the four necessary conditions and the simultaneity rule from memory — this is a statement-type question; (2) draw a resource allocation graph from a holdings-and-requests description and state whether a cycle means a deadlock, with the single-instance versus multiple-instance distinction; (3) compute Need from Max and Allocation, and run the safety algorithm to find a safe sequence — practice with the worked example and the prescribed book's exercises; (4) apply the resource-request algorithm to a specific request, knowing when the answer is "granted", "wait", or "error: exceeded maximum claim". For the mid-semester, the banker's worked example is out of scope; for the comprehensive exam, nothing here is.

Key Industry Applications

Real-world: the traffic jam near a railway track is the everyday picture of a deadlock — vehicles from both directions occupy the same stretch of road, the road is the resource, the vehicles are the processes, and no one can move. Prevention or avoidance techniques for deadlock apply to the traffic situation in the same way they apply to a set of processes.

Real-world: printers, DVD drives, and other I/O devices are the concrete example of non-shareable, limited resources. If more processes want the resource than there are instances, chances of a deadlock exist; mutual exclusion keeps the data consistent and avoids race conditions in the critical section, producer-consumer, and reader-writer settings.

Real-world: files are used through open, use, and close — the file-world version of request, use, and release — and memory is used through allocation of free space, use, and freeing the space. A system with two disk drives, where two processes each hold one drive and both need one more, is the classic small deadlock.

Real-world: the banker's algorithm — named for its banking analogy and developed by Edsger Dijkstra (1965) — is the standard method for deadlock avoidance with multiple instances, and its worked example is the one found in the prescribed book.

Where this module meets industry. Every layer of a modern system carries a deadlock policy: database engines (MySQL InnoDB, PostgreSQL, Oracle) detect lock-wait rings between transactions and roll back the cheapest victim; file servers and hypervisors order their locks to make rings impossible; and the "ignoring" strategy, far from being a joke, is the shipping default of mainstream operating systems, which is why application developers are taught transactions, timeouts, and lock ordering. If a real system ever freezes and the log shows two transactions holding each other's rows, you are looking at a resource allocation graph in production — and the four conditions tell you exactly which prevention or recovery mechanism applies.

OS Lecture 9 notes · Deadlocks

Operating Systems· postgraduate· 2026-08-15

Sections Breakdown

1Deadlocks: The Basic Picture

What a deadlock is: holding and waiting, the traffic-jam picture, finite resources and instances, and the request-use-release cycle.

2The Four Necessary Conditions of a Deadlock

Mutual exclusion, hold and wait, no preemption, and circular wait — and the rule that all four must hold simultaneously.

3Resource Allocation Graphs

Circles, squares, and dots: request and assignment edges, and what a cycle proves when resource types have one or many instances.

4Three Ways to Handle a Deadlock

Prevention, detection and recovery, or ignoring — and how prevention differs from avoidance in the information it needs.

5Deadlock Prevention: Break One of the Four Conditions

Attacking each condition in turn: the two request protocols, the two preemption protocols, and total resource ordering.

6Deadlock Avoidance

Safe and unsafe states, claim edges for single-instance systems, and the banker's algorithm with its data structures and worked examples.

7Exam Guidance Summary

The professor's exam strategy: the first half of the deadlock module belongs to the mid-semester, and the banker's worked example does not.

8Key Industry Applications

Where deadlock ideas meet real systems: database lock detection, lock ordering, and the ignoring strategy of mainstream operating systems.

Postgraduate students studying Operating Systems

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Deadlocks: The Basic Picture

Must-know: A deadlock is a set of processes each holding a resource and waiting to acquire a resource held by another process in the set; holding and waiting are the two phrases at the heart of the topic.

Top pitfall: Thinking a process must hold a resource to be part of a deadlock — a process holding nothing can still be stuck in the waiting cycle.

Self-check: With two disk drives and two processes, each holding one drive and needing a second, is the system deadlocked?

Connects to: 9.2 The Four Necessary Conditions of a Deadlock

The Four Necessary Conditions of a Deadlock

Must-know: The four necessary conditions of a deadlock are mutual exclusion, hold and wait, no preemption, and circular wait; all four must occur simultaneously for a deadlock to exist — one missing condition means only chances of a deadlock, not the deadlock itself.

Top pitfall: Confusing necessary with sufficient: a single condition (for example mutual exclusion alone) is required but never enough; the four conditions must hold at the same time.

Self-check: Why is circular wait a stronger form of hold and wait?

Connects to: 9.1 Deadlocks: The Basic Picture, 9.3 Resource Allocation Graphs

Resource Allocation Graphs

Must-know: In a resource allocation graph: no cycle means no deadlock; a cycle with only one instance per resource type is a necessary and sufficient condition for a deadlock; a cycle with multiple instances is necessary but not sufficient.

Top pitfall: Declaring a deadlock from any cycle: with multiple instances a cycle may be broken later when a holder releases an instance, so the cycle alone does not prove a deadlock.

Self-check: A graph has a cycle, and every resource type has exactly one instance. Is the system deadlocked?

Connects to: 9.2 The Four Necessary Conditions of a Deadlock, 9.6 Deadlock Avoidance

Three Ways to Handle a Deadlock

Must-know: The three ways to handle a deadlock are prevention, detection and recovery, and ignoring; prevention breaks one of the four necessary conditions and needs no a priori information, while avoidance needs each process to declare up front how much of each resource it will use.

Top pitfall: Using prevention and avoidance as synonyms — they differ in the a priori information they need and in what they guarantee.

Self-check: Which strategy does a mainstream operating system typically adopt for deadlocks, and why?

Connects to: 9.5 Deadlock Prevention: Break One of the Four Conditions, 9.6 Deadlock Avoidance

Deadlock Prevention: Break One of the Four Conditions

Must-know: Prevention attacks each condition: mutual exclusion cannot be prevented for non-shareable resources; hold and wait is broken by requesting all resources up front or only when holding nothing; no preemption is broken by release-and-restart or by preempting from waiting processes; circular wait is broken by a total ordering F with requests in increasing order, which rules out circular wait by contradiction.

Top pitfall: Forgetting the 'or equal to' ban in resource ordering — a process may never request a resource with a number lower than or equal to one it already holds.

Self-check: Why can mutual exclusion not be prevented for a printer?

Connects to: 9.2 The Four Necessary Conditions of a Deadlock, 9.4 Three Ways to Handle a Deadlock

Deadlock Avoidance

Must-know: Avoidance keeps the system in safe states: all deadlocks are unsafe states but not all unsafe states are deadlocks. For multiple instances, the banker's algorithm uses Need = Max - Allocation, the safety algorithm (Work = Available; finish any process with Need <= Work, adding its Allocation to Work), and the resource-request algorithm (check Request <= Need, then Request <= Available, then pretend-allocate and run safety). The class safe sequence is P1, P3, P4, P0, P2, and request (1 0 2) by P1 is granted because the pretend state is safe.

Top pitfall: Confusing the subtraction from the available pool while a process runs with the addition of its maximum when it completes; also confusing unsafe states with deadlocks.

Self-check: In the worked example, why can P1's request (1 0 2) be granted immediately?

Connects to: 9.3 Resource Allocation Graphs, 9.4 Three Ways to Handle a Deadlock, 9.5 Deadlock Prevention: Break One of the Four Conditions

Exam Guidance Summary

Must-know: The mid-semester covers the first half of the deadlock module, up through avoidance; the comprehensive exam includes everything. The four conditions with the simultaneity rule, the necessary-and-sufficient versus necessary-but-not-sufficient cycle distinction, and Need = Max - Allocation are exam essentials.

Top pitfall: Spending the mid-semester on the banker's algorithm worked example, which was explicitly stated as not part of the mid-semester.

Self-check: Which part of the deadlock module belongs to the mid-semester, and which is reserved for the comprehensive exam?

Connects to: 9.1 Deadlocks: The Basic Picture, 9.2 The Four Necessary Conditions of a Deadlock, 9.3 Resource Allocation Graphs, 9.6 Deadlock Avoidance

Key Industry Applications

Must-know: Deadlock ideas map to real systems: the traffic jam is the everyday deadlock picture; printers and DVD drives are non-shareable limited resources; files and memory follow request-use-release; and the banker's algorithm is the standard multiple-instance avoidance method credited to Dijkstra via the banking analogy.

Top pitfall: Reading the banker's algorithm as the work of a discoverer named Banker — the name comes from the banking analogy, and the algorithm is due to Dijkstra.

Self-check: What does the banker's algorithm have to do with banking?

Connects to: 9.1 Deadlocks: The Basic Picture, 9.6 Deadlock Avoidance

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.