Session 3.5: Deadlock Prevention and Avoidance

Strategies to prevent deadlock occurrence and algorithms to avoid unsafe states

Module 3 2.5 Hours Theory & Algorithms

Learning Objectives

By the end of this session, you will be able to:
  • Understand deadlock prevention by eliminating necessary conditions
  • Distinguish between prevention and avoidance approaches
  • Define safe and unsafe states in resource allocation
  • Implement and analyze the Banker's algorithm
  • Apply resource request algorithms for deadlock avoidance
  • Compare trade-offs between different approaches
Key Concept

Prevention eliminates the possibility of deadlock by ensuring at least one necessary condition cannot hold. Avoidance allows all conditions but uses algorithms to ensure the system never enters an unsafe state.

Prevention Approach

Eliminate one or more of the four necessary conditions for deadlock. Conservative but may reduce system efficiency.

Avoidance Approach

Allow all necessary conditions but use algorithms to ensure safe resource allocation. More flexible but requires advance knowledge.

Deadlock Prevention Strategies

Prevention works by ensuring that at least one of the four necessary conditions for deadlock cannot occur in the system.

1. Eliminating Mutual Exclusion

Make Resources Shareable
Possible for:
  • Read-only files
  • Shared memory (read-only)
  • Some network resources
Not possible for:
  • Printers, scanners
  • Write access to files
  • Critical sections
Example: Spooling System
- Instead of direct printer access
- Jobs written to disk spool
- Printer daemon processes queue
- Eliminates mutual exclusion for printer

2. Eliminating Hold and Wait

Require All Resources at Once
Protocol 1: All-or-Nothing Allocation
- Process must request all resources before execution
- If any resource unavailable, wait without holding any
- Only start execution when all resources granted

Example:
Process needs: Printer, Scanner, File A, File B
- Request all four resources simultaneously
- If any unavailable, release all and wait
- Proceed only when all four are available

Advantages:
+ Eliminates hold-and-wait condition
+ Simple to implement

Disadvantages:
- Low resource utilization
- Starvation possible
- May not know all resources in advance
Release Before Requesting
Protocol 2: Release and Re-request
- Process can hold resources initially
- To request new resource, must release all current resources
- Request all needed resources (old + new)
- Re-acquire in single atomic operation

Example:
Process holds: Printer, File A
Needs additional: Scanner
1. Release Printer and File A
2. Request Printer, File A, and Scanner together
3. Wait until all three available
4. Proceed with all resources

Advantages:
+ Eliminates hold-and-wait
+ More flexible than Protocol 1

Disadvantages:
- Resource preemption overhead
- Possible data loss if resources released
- Still low utilization

3. Eliminating No Preemption

Allow Resource Preemption
Preemption Protocols:

Protocol 1: Preempt Requesting Process
- If process P1 requests resource held by P2
- If P2 is waiting for other resources
- Preempt all resources from P2
- Give requested resource to P1
- P2 restarts when all its resources available

Protocol 2: Preempt Based on Priority
- Higher priority process can preempt lower priority
- Preempted process must restart
- Can lead to starvation of low-priority processes

Suitable for:
✓ CPU (context switching)
✓ Memory (swapping/paging)
✓ Registers (save/restore)

Not suitable for:
✗ Printers (cannot undo printing)
✗ Mutex locks (data corruption)
✗ Database transactions (consistency)

4. Eliminating Circular Wait

Resource Ordering
Ordered Resource Allocation:
1. Assign unique number to each resource type
   R1 = Printer (1)
   R2 = Scanner (2)  
   R3 = File System (3)
   R4 = Network (4)

2. Processes must request resources in increasing order
   - Can request R1, then R2, then R3
   - Cannot request R1 after requesting R2

3. If need lower-numbered resource, must release higher ones

Example Implementation:
Process P1: Needs Printer(1) and Network(4)
- Request Printer(1) first ✓
- Then request Network(4) ✓
- Order: 1 → 4 (increasing) ✓

Process P2: Needs Network(4) and Scanner(2)  
- Request Scanner(2) first ✓
- Then request Network(4) ✓
- Order: 2 → 4 (increasing) ✓

Proof: No circular wait possible
- If Pi waits for Pj, then Pi requested higher-numbered resource
- Pj cannot wait for Pi (would violate ordering)
- No cycle can form

Deadlock Avoidance Concept

Deadlock avoidance allows all four necessary conditions to exist but uses algorithms to ensure the system never enters a state where deadlock is possible.

Key Requirements for Avoidance
  • Advance Information: Must know maximum resource needs of each process
  • Dynamic Allocation: Resources allocated dynamically based on current state
  • Safe State Maintenance: System must always remain in a safe state
  • Conservative Approach: May deny requests even when resources are available

Resource Allocation State

The resource allocation state is defined by:

  • Available: Number of available instances of each resource type
  • Allocation: Number of instances currently allocated to each process
  • Max: Maximum number of instances each process may need
  • Need: Remaining resource needs (Need = Max - Allocation)

Example System State

System: 3 resource types (A, B, C)
Total instances: A=10, B=5, C=7

Current state:
Process | Allocation | Max | Need
        | A  B  C    | A B C | 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

Available: A=3, B=3, C=2

Question: Is this a safe state?
Answer: Need to check if there exists a safe sequence...

Safe vs Unsafe States

Safe State

A state is safe if there exists a safe sequence of processes such that all processes can complete their execution.

Safe Sequence Properties:
  • For each Pi, resources needed ≤ available + allocated to Pj (j < i)
  • Pi can wait until all Pj (j < i) finish
  • When Pj finishes, Pi gets needed resources
  • Pi completes and releases all resources
Unsafe State

A state is unsafe if no safe sequence exists. This doesn't guarantee deadlock, but deadlock is possible.

Unsafe State Characteristics:
  • No process can complete with available resources
  • All processes need more than currently available
  • System may enter deadlock if processes request maximum
  • Avoidance algorithms prevent entering unsafe states

Safe Sequence Example

Finding Safe Sequence for Previous Example
Available: A=3, B=3, C=2

Step 1: Check P1 (Need: 1,2,2)
- Need ≤ Available? (1,2,2) ≤ (3,3,2) ✓
- P1 can finish, releases (2,0,0)
- New Available: (3,3,2) + (2,0,0) = (5,3,2)

Step 2: Check P3 (Need: 0,1,1)  
- Need ≤ Available? (0,1,1) ≤ (5,3,2) ✓
- P3 can finish, releases (2,1,1)
- New Available: (5,3,2) + (2,1,1) = (7,4,3)

Step 3: Check P4 (Need: 4,3,1)
- Need ≤ Available? (4,3,1) ≤ (7,4,3) ✓  
- P4 can finish, releases (0,0,2)
- New Available: (7,4,3) + (0,0,2) = (7,4,5)

Step 4: Check P2 (Need: 6,0,0)
- Need ≤ Available? (6,0,0) ≤ (7,4,5) ✓
- P2 can finish, releases (3,0,2)
- New Available: (7,4,5) + (3,0,2) = (10,4,7)

Step 5: Check P0 (Need: 7,4,3)
- Need ≤ Available? (7,4,3) ≤ (10,4,7) ✓
- P0 can finish

Safe sequence found: P1 → P3 → P4 → P2 → P0
Therefore, the state is SAFE!

Banker's Algorithm

The Banker's algorithm is a deadlock avoidance algorithm that ensures the system always remains in a safe state by checking resource allocation requests before granting them.

Algorithm Concept

Named after the banking system where a banker ensures they can satisfy all customers' credit needs. The algorithm simulates resource allocation to check if the resulting state would be safe.

Data Structures

Let n = number of processes, m = number of resource types

Available[m]: Available instances of each resource type
Max[n][m]: Maximum demand of each process for each resource type  
Allocation[n][m]: Currently allocated instances to each process
Need[n][m]: Remaining need of each process
             Need[i][j] = Max[i][j] - Allocation[i][j]

Work[m]: Working copy of Available (used in algorithm)
Finish[n]: Boolean array to track completed processes

Safety Algorithm

Step-by-Step Safety Check
Algorithm: Check if current state is safe

1. Initialize:
   Work = Available
   Finish[i] = false for all i

2. Find process Pi such that:
   a) Finish[i] == false
   b) Need[i] ≤ Work
   
   If no such Pi exists, go to step 4

3. Simulate Pi completion:
   Work = Work + Allocation[i]
   Finish[i] = true
   Go to step 2

4. Check result:
   If Finish[i] == true for all i:
       System is in safe state
   Else:
       System is in unsafe state

Time Complexity: O(m × n²)
Space Complexity: O(m + n)

Banker's Algorithm Implementation

function bankers_algorithm(processes, resources, available, max, allocation):
    n = len(processes)  # number of processes
    m = len(resources)  # number of resource types
    
    # Calculate need matrix
    need = [[max[i][j] - allocation[i][j] for j in range(m)] for i in range(n)]
    
    # Check if current state is safe
    def is_safe():
        work = available[:]
        finish = [False] * n
        safe_sequence = []
        
        for _ in range(n):
            found = False
            for i in range(n):
                if not finish[i] and all(need[i][j] <= work[j] for j in range(m)):
                    # Process i can finish
                    for j in range(m):
                        work[j] += allocation[i][j]
                    finish[i] = True
                    safe_sequence.append(i)
                    found = True
                    break
            
            if not found:
                return False, []
        
        return True, safe_sequence
    
    return is_safe()

# Example usage:
processes = ['P0', 'P1', 'P2', 'P3', 'P4']
resources = ['A', 'B', 'C']
available = [3, 3, 2]
max = [[7,5,3], [3,2,2], [9,0,2], [2,2,2], [4,3,3]]
allocation = [[0,1,0], [2,0,0], [3,0,2], [2,1,1], [0,0,2]]

safe, sequence = bankers_algorithm(processes, resources, available, max, allocation)
print(f"Safe: {safe}, Sequence: {sequence}")

Resource Request Algorithm

When a process requests resources, the system must decide whether to grant the request immediately or make the process wait to avoid entering an unsafe state.

Request Processing Steps

Algorithm for Processing Resource Request
Let Request[i] be the request vector for process Pi
Request[i][j] = k means Pi wants k instances of resource type Rj

Step 1: Validity Check
If Request[i] ≤ Need[i]:
    Continue to step 2
Else:
    Raise error (process exceeded maximum claim)

Step 2: Availability Check  
If Request[i] ≤ Available:
    Continue to step 3
Else:
    Pi must wait (insufficient resources)

Step 3: Simulate Allocation
Temporarily modify state:
    Available = Available - Request[i]
    Allocation[i] = Allocation[i] + Request[i]  
    Need[i] = Need[i] - Request[i]

Step 4: Safety Check
Run safety algorithm on new state:
If safe:
    Grant request (make changes permanent)
Else:
    Deny request (restore original state)
    Pi must wait

Example: Resource Request Processing

Current State:
Process | Allocation | Need     | Max
        | A  B  C    | A  B  C  | A  B  C
--------|-----------|----------|--------
P0      | 0  1  0    | 7  4  3  | 7  5  3
P1      | 2  0  0    | 1  2  2  | 3  2  2
P2      | 3  0  2    | 6  0  0  | 9  0  2
P3      | 2  1  1    | 0  1  1  | 2  2  2
P4      | 0  0  2    | 4  3  1  | 4  3  3

Available: A=3, B=3, C=2

Request: P1 requests (1,0,2)

Step 1: Check Request ≤ Need
(1,0,2) ≤ (1,2,2) ✓ Valid

Step 2: Check Request ≤ Available  
(1,0,2) ≤ (3,3,2) ✓ Sufficient resources

Step 3: Simulate allocation
New Available: (3,3,2) - (1,0,2) = (2,3,0)
New Allocation[P1]: (2,0,0) + (1,0,2) = (3,0,2)
New Need[P1]: (1,2,2) - (1,0,2) = (0,2,0)

Step 4: Check if new state is safe
Try to find safe sequence with Available=(2,3,0)...
- P1 needs (0,2,0) ≤ (2,3,0) ✓ Can finish
- After P1: Available = (2,3,0) + (3,0,2) = (5,3,2)
- Continue checking other processes...

If safe sequence found: Grant request
If no safe sequence: Deny request, restore original state

Implementation Example

def process_request(process_id, request, available, allocation, need, max_claim):
    n = len(allocation)
    m = len(available)
    
    # Step 1: Check if request is valid
    if not all(request[j] <= need[process_id][j] for j in range(m)):
        return False, "Request exceeds maximum claim"
    
    # Step 2: Check if resources are available
    if not all(request[j] <= available[j] for j in range(m)):
        return False, "Insufficient resources available"
    
    # Step 3: Simulate allocation
    # Save current state
    old_available = available[:]
    old_allocation = [row[:] for row in allocation]
    old_need = [row[:] for row in need]
    
    # Modify state
    for j in range(m):
        available[j] -= request[j]
        allocation[process_id][j] += request[j]
        need[process_id][j] -= request[j]
    
    # Step 4: Check safety
    safe, sequence = is_safe_state(available, allocation, need)
    
    if safe:
        return True, f"Request granted. Safe sequence: {sequence}"
    else:
        # Restore original state
        available[:] = old_available
        allocation[:] = old_allocation
        need[:] = old_need
        return False, "Request denied - would lead to unsafe state"

Prevention vs Avoidance Comparison

Prevention Approach
Advantages:
  • Simple to implement
  • No need for advance information
  • Guarantees no deadlock
  • Works with any resource allocation pattern
Disadvantages:
  • Low resource utilization
  • Reduced system throughput
  • May cause starvation
  • Overly conservative
Avoidance Approach
Advantages:
  • Better resource utilization
  • Higher system throughput
  • More flexible allocation
  • Allows all necessary conditions
Disadvantages:
  • Requires advance knowledge of maximum needs
  • Complex algorithms (O(m×n²))
  • Runtime overhead for safety checks
  • Fixed number of processes and resources

Practical Considerations

Real-World Application
Prevention is suitable for:
  • Simple embedded systems
  • Real-time systems with predictable patterns
  • Systems where safety is critical
  • Resource-constrained environments
Avoidance is suitable for:
  • Batch processing systems
  • Systems with known workloads
  • High-performance computing
  • Database management systems

Performance Comparison

Resource Utilization
  • Prevention: 40-60%
  • Avoidance: 70-85%
  • Detection: 85-95%
Algorithm Complexity
  • Prevention: O(1)
  • Avoidance: O(m×n²)
  • Detection: O(m×n²)
Information Required
  • Prevention: None
  • Avoidance: Maximum needs
  • Detection: Current state

Hybrid Approaches

Combining Strategies

Modern systems often combine multiple approaches:

  • Layered approach: Prevention for critical resources, avoidance for others
  • Resource-specific: Different strategies for different resource types
  • Adaptive systems: Switch strategies based on system load
  • Timeout mechanisms: Combine with detection and recovery

Session Summary

Key Takeaways:
  • Prevention Strategies: Eliminate one of the four necessary conditions
  • Resource Ordering: Most practical prevention method for circular wait
  • Safe States: States where all processes can complete execution
  • Banker's Algorithm: Classic avoidance algorithm ensuring safe states
  • Request Processing: Dynamic safety checking before resource allocation
  • Trade-offs: Prevention is simple but inefficient; avoidance is complex but flexible
Study Tips:
  • Practice Banker's algorithm with different scenarios
  • Understand safe vs unsafe state differences
  • Work through resource request examples
  • Compare prevention method trade-offs
Prevention Methods Summary:
  • Mutual Exclusion: Spooling, read-only sharing
  • Hold and Wait: All-or-nothing, release-and-request
  • No Preemption: Forced preemption, priority-based
  • Circular Wait: Resource ordering (most practical)
Avoidance Components:
  • State Information: Available, Allocation, Max, Need
  • Safety Algorithm: Check for safe sequences
  • Request Algorithm: Simulate and verify safety
  • Complexity: O(m×n²) time, O(m+n) space
Next Session:

Session 3.6: Deadlock Detection and Recovery
Algorithms for detecting deadlock occurrence and methods for system recovery