Hone logo
Hone
Problems

Deadlock Detection in a Resource Allocation System

In concurrent programming, deadlocks are a critical issue that can halt system execution. A deadlock occurs when a set of processes are blocked indefinitely, each waiting for a resource that is held by another process in the set. This challenge asks you to implement a deadlock detection algorithm to identify such situations within a simulated resource allocation system.

Problem Description

You need to design and implement a Python function, detect_deadlock, that takes the current state of a resource allocation system and returns whether a deadlock exists. The system can be represented by the resources available and the requests made by processes.

Requirements:

  1. Input Representation: The function will receive two main pieces of information:

    • resources: A dictionary where keys are resource names (strings) and values are the total number of instances of that resource available.
    • allocations: A dictionary of dictionaries. The outer dictionary's keys are process IDs (strings). The inner dictionary's keys are resource names (strings), and values are the number of instances of that resource currently allocated to the process.
    • requests: A dictionary of dictionaries, similar to allocations. The outer dictionary's keys are process IDs (strings). The inner dictionary's keys are resource names (strings), and values are the number of instances of that resource currently requested by the process.
  2. Algorithm: You should implement a Banker's Algorithm-like approach or a graph-based cycle detection algorithm to identify deadlocks. The core idea is to simulate the system's potential future states to see if all processes can eventually complete.

  3. Output: The function should return True if a deadlock is detected, and False otherwise.

Expected Behavior:

  • If there's a scenario where no process can acquire its requested resources to complete, even after other processes release their resources, a deadlock exists.
  • If all processes can eventually complete (i.e., release all their held resources), then no deadlock exists.

Edge Cases:

  • No processes: If allocations and requests are empty, there's no deadlock.
  • No resources: If resources is empty but processes have allocations/requests, this implies an issue, but the primary focus is on circular dependencies.
  • Processes requesting zero resources: These processes can be considered "finished" or able to finish immediately.
  • Processes holding zero resources: These processes don't contribute to holding resources, but their requests still matter.

Examples

Example 1:

Input:
resources = {"R1": 1, "R2": 1}
allocations = {"P1": {"R1": 1}, "P2": {"R2": 1}}
requests = {"P1": {"R2": 1}, "P2": {"R1": 1}}

Output:
True

Explanation:
P1 holds R1 and requests R2.
P2 holds R2 and requests R1.
Neither process can proceed because the resource they need is held by the other. This forms a classic deadlock.

Example 2:

Input:
resources = {"R1": 2, "R2": 1}
allocations = {"P1": {"R1": 1}, "P2": {"R1": 1}}
requests = {"P1": {"R2": 1}}

Output:
False

Explanation:
Initially, P1 holds 1 R1 and requests 1 R2. P2 holds 1 R1 and requests nothing.
Available resources: {"R1": 0, "R2": 1}.
P2 can finish as it has no outstanding requests. After P2 finishes, it releases its R1.
Now, available resources are: {"R1": 1, "R2": 1}.
P1 can acquire R2 and finish.
Since all processes can finish, there is no deadlock.

Example 3:

Input:
resources = {"CPU": 1, "MEM": 2}
allocations = {"TaskA": {"CPU": 1}, "TaskB": {"MEM": 1}}
requests = {"TaskA": {"MEM": 1}, "TaskB": {"CPU": 1}}

Output:
True

Explanation:
TaskA holds CPU and needs MEM.
TaskB holds MEM and needs CPU.
This is a deadlock.

Constraints

  • The number of processes will be between 0 and 100.
  • The number of resource types will be between 0 and 50.
  • Resource names and process IDs will be strings.
  • All resource counts, allocations, and requests will be non-negative integers.
  • The sum of allocated resources for a given type will not exceed the total available resources of that type.
  • The algorithm should ideally run in a time complexity that is reasonable for the given constraints (e.g., polynomial in the number of processes and resources).

Notes

  • You'll need to keep track of available resources. Initially, this is resources minus the sum of all current allocations.
  • A crucial step is to identify processes that can finish given the currently available resources.
  • If a process can finish, its allocated resources become available for other processes. This is the key to breaking potential deadlocks.
  • Consider how to efficiently update the state of available resources and process completion.
  • A directed graph representation (where nodes are processes and resources, and edges represent allocation/request) can be a helpful way to visualize and detect cycles, but a simulation-based approach is also valid.
Loading editor...
python