June 29, 2025
Priority Inversion and Priority Inheritance in FreeRTOS

Priority Inversion and Priority Inheritance in FreeRTOS

When working with real-time operating systems (RTOS) like FreeRTOS, task scheduling and resource management are key components of building efficient and reliable systems. One of the challenges faced in real-time systems is priority inversion, a scenario where tasks with higher priority are forced to wait for lower-priority tasks to release a resource they need. This can lead to significant delays and affect the performance of time-critical applications.

Fortunately, FreeRTOS provides a mechanism called priority inheritance to mitigate the effects of priority inversion. In this article, we will explore these concepts in detail and show how they are handled within the ESP32 IDF (IoT Development Framework) when using FreeRTOS.

What is Priority Inversion?

Priority inversion happens when a lower-priority task holds a resource (such as a mutex) that a higher-priority task needs to execute. If a medium-priority task preempts the low-priority task, the high-priority task is blocked, even though it should have the highest priority. This can result in significant delays in the execution of time-critical tasks.

Example Scenario

Consider the following scenario with three tasks:

  • Task A: Highest priority (Priority 3)
  • Task B: Medium priority (Priority 2)
  • Task C: Lowest priority (Priority 1)

Now, assume the following sequence:

  • Task C starts executing and acquires a mutex resource.
  • Task A (highest priority) is ready to execute but is blocked because it needs the mutex held by Task C.
  • Task B (medium priority) becomes ready and preempts Task C.
  • Task A remains blocked, waiting for Task C to release the mutex, but Task C cannot run because Task B is occupying the CPU.

In this case, Task A (the highest-priority task) is effectively “inverted” by Task B (the medium-priority task), which leads to unnecessary delays and can compromise the system’s real-time performance.

Consequences of Priority Inversion

Priority inversion can have severe consequences in real-time systems:

  • Missed Deadlines: High-priority tasks may miss their deadlines if they are delayed by lower-priority tasks.
  • Reduced System Predictability: The ability to predict the behavior of the system diminishes, which is critical for safety-critical or time-sensitive applications.
  • Increased Latency: The delays introduced by priority inversion can cause significant latency in time-critical applications like sensor readings, motor control, or communication protocols.

Priority Inheritance

To solve the problem of priority inversion, priority inheritance can be used.

How Priority Inheritance Works:

  • When a lower-priority task holds a resource that a higher-priority task needs, the RTOS temporarily raises the priority of the lower-priority task to match that of the higher-priority task.
  • This ensures that the lower-priority task can complete quickly, release the resource, and allow the high-priority task to resume.
  • Once the lower-priority task releases the resource, its priority is reverted back to its original value.

How Priority Inheritance Works in FreeRTOS

FreeRTOS automatically enables priority inheritance for mutexes. When a higher-priority task waits for a mutex, the lower-priority task that currently holds the mutex inherits the priority of the higher-priority task until it releases the mutex.

Example :

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

// Mutex handle
SemaphoreHandle_t xMutex;

// Task A (High priority)
void taskA(void *pvParameters) {
    printf("Task A (High priority) started\n");
    
    // Attempt to take the mutex (wait indefinitely)
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
        // Simulate critical section
        printf("Task A acquired the mutex and is working on the shared resource\n");
        vTaskDelay(500 / portTICK_PERIOD_MS);  // Simulate work (e.g., processing)
        printf("Task A finished its work and released the mutex\n");
        
        // Release the mutex
        xSemaphoreGive(xMutex);
    }

    // Task A is done
    vTaskDelete(NULL);
}

// Task B (Medium priority)
void taskB(void *pvParameters) {
    printf("Task B (Medium priority) started\n");
    
    // Simulate some work, but do not try to acquire the mutex
    for (int i = 0; i < 10; i++) {
        printf("Task B is doing some non-critical work\n");
        vTaskDelay(300 / portTICK_PERIOD_MS);  // Simulate work
    }
    
    // Task B is done
    vTaskDelete(NULL);
}

// Task C (Low priority)
void taskC(void *pvParameters) {
    printf("Task C (Low priority) started\n");
    

    xSemaphoreTake(xMutex, portMAX_DELAY);  // Take the mutex
        // Simulate holding the mutex for a long time
    printf("Task C is holding the mutex\n");
    // Simulate work while holding the mutex
    vTaskDelay(2000 / portTICK_PERIOD_MS);  // Simulate long critical section (holding mutex)
    
    printf("Task C finished its work and is releasing the mutex\n");
    
    // Release the mutex
    xSemaphoreGive(xMutex);

    // Task C is done
    vTaskDelete(NULL);
}

void app_main(void) {
    // Create the mutex with priority inheritance enabled by default
    xMutex = xSemaphoreCreateMutex();
    if (xMutex == NULL) {
        printf("Failed to create mutex\n");
        return;
    }


    // Create Task C (low priority)
    xTaskCreate(taskC, "Task C", 2048, NULL, 1, NULL);  // Priority 1 (Low priority)


    // Create Task A (high priority)
    xTaskCreate(taskA, "Task A", 2048, NULL, 3, NULL);  // Priority 3 (High priority)

    // Create Task B (medium priority)
    xTaskCreate(taskB, "Task B", 2048, NULL, 2, NULL);  // Priority 2 (Medium priority)

}

Conclusion

Priority inversion can cause significant issues in real-time systems by delaying the execution of critical tasks. FreeRTOS provides a solution through priority inheritance, which helps prevent lower-priority tasks from blocking higher-priority tasks when mutexes are involved. By enabling priority inheritance, developers can ensure that the system behaves as expected even in complex scenarios where multiple tasks contend for shared resources.

Leave a Reply

Your email address will not be published. Required fields are marked *