In this lesson, you will learn how to map task resource dependencies to identify and visualize the "circular wait" conditions that trigger system-wide deadlocks.
Understanding the Circular Wait
A deadlock occurs when two or more tasks are permanently blocked, each waiting for a resource held by the other. In a complex RTOS environment, these dependencies are rarely obvious. To detect them, we use a Task Dependency Graph, where nodes represent tasks and resources, and directed edges represent "hold" or "request" relationships.
A system is deadlocked if and only if there is a cycle in this graph. If Task A holds Mutex 1 and requests Mutex 2, while Task B holds Mutex 2 and requests Mutex 1, the cycle Task A -> Mutex 2 -> Task B -> Mutex 1 -> Task A is formed. Neither task can proceed, leading to a permanent stall.
Visualizing the Logic
Consider two tasks competing for hardware peripherals:
// Task A Logic
TakeMutex(Mutex_UART);
// ... processing ...
TakeMutex(Mutex_SPI); // Potential cycle point
// Task B Logic
TakeMutex(Mutex_SPI);
// ... processing ...
TakeMutex(Mutex_UART); // Potential cycle point
If Task A acquires Mutex_UART at the same time Task B acquires Mutex_SPI, both will suspend indefinitely waiting for the other’s resource.
Detection Strategy
To identify these cycles in your own logic, document the "acquisition order" of your resources across all tasks. If you detect that Task 1 locks resources in the order [A, B] while Task 2 locks them in the order [B, A], you have identified a high-risk deadlock path. In complex systems, we analyze these paths by checking if a task holding a resource ever requests a resource that is currently held by a task that—directly or indirectly—requires the first resource.
By enforcing a strict resource hierarchy (e.g., always locking Mutex_UART before Mutex_SPI regardless of the task), you break the potential for a circular dependency, rendering the cycle impossible to form.
Key Takeaway: A deadlock is mathematically guaranteed if your task dependency graph contains a closed loop; you can prevent this by enforcing a global, strict locking order across all concurrent tasks.