Deadlock and Starvation • Deadlock: A set of Processes holding resources and blocked waiting for others held by a processes in the same wait set. • Starvation: Resource is always granted to other waiting processes • Example: 2 tape drives, P1 and P2 each hold one and need both • Example: P0: wait(A); wait(B); P1: wait(B); wait(A); • Resource: The narrow bridge • Deadlock Resolution: Cars back up (preemption and rollback) • Starvation is possible. Conditions Necessary for Deadlock • Hold and wait: Processes partially allocate resources • Limited Resources: There is a limited number of resources of a particular type. Processes will block if requesting a limited that is unavailable. • No preemption: A resource can be released only voluntarily by the process holding it. • Circular wait: there exists a process set {P0, P1, …, P0} where P0 is waiting for a resource that is held by P1, P1 is waiting for a resource that is held by P2, …, Pn–1 is waiting for a resource that is held by P0. P0 wait (A); wait (B); P1 wait(B) wait(A) Exercise Refer to the above figure 1. How are all four conditions present? 2. How can deadlock be prevented, avoided, and detected? Directed Resource Allocation Graph • Process Graph: A set of vertices & edges. Two vertex categories: 1. Circles: represent Processes {P1, P2, …, Pn} 2. Rectangles: represent Resource types {R1,R2,…,Rm} Two edge categories 1. Pi requests resource type Rj: PiRj 2. Resource Rj instance assigned to Pi: RjPi Resource categories: CPU cycles, memory files, I/O devices Access: request, utilize, then release • Resource Type with 4 instances • Pi requests Rj instance Pi • Pi holding Rj instance Pi Graph Cycles • No cycles no deadlock. • cycles – Deadlock if there is only one instance per resource type – Deadlock possibility several instances per resource type and all processes are waiting for a resource No Deadlock Deadlock Possible Deadlock class B implements Runnable; class A implements Runnable; { private Lock one, two; { private Lock one, two; public(Lock one,Lock two) public(Lock one,Lock two) { this.one = one; { this.one = one; this.two = two; this.two = two; } } public void run() public void run() { try { try { two.lock(); { one.lock(); doSomething(); doSomething(); one.lock(); two.lock(); doSomethingElse(); doSomethingElse(); } } finally finally { two.unlock(); { two.unlock(); one.unlock(); one.unlock(); } } } } } } Deadlock possible depending on timing, but sometimes will not occur Handling Deadlocks • Prevention: Eliminate one of the four necessary conditions • Avoidance: Ensure that the system will never enter a deadlock state. • Recovery: Allow the system to enter a deadlock state and then recover. • Ignore: Most operating systems, including UNIX and WINDOWS, pretend that deadlocks never occur. It is up to application programs to handle. Deadlock Prevention Eliminate one of the necessary conditions • Hold and Wait – sharable resources like read-only files are deadlock free • Limited Resources – Resources with unlimited instances are deadlock free. • No Preemption – Release all resources instead of blocking on a resource request. The preempted resources are added to the resource wait list. – Restart when all requested resources are available. • Circular Wait (Disadvantage: Low resource utilization) 1. Impose a total ordering of resource types. Processes must request resources in an increasing order of enumeration. 2. Processes cannot request resources when already holding others. Deadlock Avoidance • The system must have advance knowledge of total needed resources • Processes will not hold a resource forever Safe state: A sequence of requests exist that can be satisfied without deadlock Safe state no deadlocks Unsafe state possibility of deadlock Avoidance disallows all unsafe states Algorithm Pseudo code System is initially safe At each request for a resource IF allocation causes an unsafe state THEN block the process ELSE grant the allocation At each resource release WHILE a blocked request can be granted safely Grant the allocation; unblock the process Resource Allocation Graph for Deadlock Avoidance • Dashed line: Pi to Rj Pi may request Rj • Solid line: Pi to Rj Pi has requested Rj. • Solid line: Rj to Pi: Rj is assigned to Pi. If resources with a single instance, implement a cycle detection algorithm (Recall Union Find algorithm from Data Structures) Dijkstra Banker’s Algorithm Original algorithm’s purpose: Prevent runs on a bank Notation request[p, r] = k means process p wants k instances of resource type r available[r] = k means there are k resources of type r available need[p,r] = k means process p potentially needs k resources of type r allocated[p,r] = k means process p owns k resources of type r Pseudo code upon processor p request for resource r 1. Throw Exception IF request[p,r[ > need[p,r] 2. 3. IF request[p,r] > available[r], block process p Tentatively allocate requested resources to process p: available[r] -= request[p,r]; allocated[p,r] += request[p,r]; need[p] -= request[p,r] 4. IF system state is safe THEN allocation is okay ELSE restore original state and block process p Safe State Algorithm Safety Algorithm 1. Let work and finish be arrays of length R and P, respectively. 2. Copy available to work FOR p = 1 to P, finish [p] = false 3. WHILE a p exists such that for all r, finish [p]=false AND need[p, r] work[r] THEN for all r, work[r] += allocated[p, r] finish[i]=true 4. IF finish[p]==true for all p, then safe system state (allocate resources) ELSE block process Data structures for this algorithm: P processes, R resources Available: available[r]=k k instances of resource r are available Max: max[p, r]=k Process p may request up to k of resource r Allocated: allocated[p, r]=k Process p owns k instances of resource r Need: need[p, r] = k Process p may need k more of resource r Note: need [p,r] = max[p, r] – allocation [p,r] Deadlock Avoidance Example 5 processes P0 through P4 and 3 resources (A,B,C) Resource A has 10 instances Resource B has 5 instances • The system state: Safe Resource C has 7 instances. – < P1, P3, P4, P2, P0> satisfies the safety criteria. Need = Max – Allocated ABC ABC ABC • P1 now requests (1,0,2). P0 7 4 3 = 7 5 3 – 0 1 0 – Request Need P1 1 2 2 = 3 2 2 – 2 0 0 – Request Available P2 6 0 0 = 9 0 2 – 3 0 2 – Execute safety algorithm: P3 0 1 1 = 2 2 2 – 2 1 1 – <P1, P3, P4, P0, P2> satisfies the safety criteria P4 4 3 1 = 4 3 3 – 0 0 2 Available = 3 3 2 • Questions: – Is P4 request for (3,3,0) safe? – Is P2 request for (0,2,0) safe? Deadlock Detection Allow Deadlock, detect its occurrence, recover Design Issues • • • • • When, and how often, to invoke the detection algorithm? Is it possible to detect the cause? How often is a deadlock is likely to occur? How many processes are part of the deadlock? Which group of processes should we abort? – All involved in the deadlock? – One at a time till the deadlock cycle is eliminated? • Can we roll back to a safe state and try again? – What is the same process is always the victim – How many rollbacks should we allow? • How to determine the cost of recovery? – Process priority and type (interactive or batch) – Process run time, and the estimated time to completion. – Resources the process has used and those still needed Deadlock Detection Single resource instances Single Instance • Maintain wait graph – Nodes are processes. – Pi Pj if Pi is waiting for Pj • Periodically invoke an algorithm to detect a cycle in the graph • The text claims cycle detection requires O(|V|2). Is that true? Resource allocation graph wait-for graph Deadlock Detection Multiple Resource Instance Algorithm Data structures for this algorithm: P processes, R resources Available: Allocated: Request: available[r]=k k instances of resource r are available allocated[p, r]=k Process p owns k instances of resource r request[p, r] = k Process p requests k instances of resource r Let work and finish be arrays of length R and P, respectively Copy available to work FOR all p and r // no circular wait if process doesn’t hold any resources IF allocated[p,r] 0, then finish[p] = false ELSE finish[p] = true // No circular wait for a process that can be fully satisfied WHILE p exists where for all r, finish[p] == false and request[p,r] work[r] SET work[p] += allocated[p,r] AND finish[p] = true IF finish[p] == false, for some p, 1 p P THEN the system and process p is in deadlocked Deadlock Detection Example Description of the system state Five processes: P0 through P4 Three resource types A has 7 instances B has 2 instances C has 6 instances Allocated Request Available ABC ABC ABC P0 0 1 0 000 000 P1 2 0 0 202 P2 3 0 3 000 P3 2 1 1 100 P4 0 0 2 002 • Sequence <P0, P2, P3, P1, P4> causes finish[p] = true for all p • If P2 requests a type C resource, the request array becomes: P0 P1 P2 P3 P4 ABC 000 201 001 100 002 • We can reclaim P0 resources, but there are not sufficient resources to fulfill the other requests • Deadlock involves P1, P2, P3, and P4 Conclusion • Most current operating systems ignore deadlocks. It is left to the application developer to handle • There is not one approach that is sufficient • The eventual solution is to combine the three basic approaches of prevention, avoidance, and detection • Different resource classes would employ a selected solution