Skip to content

Priority Inversion and How to Handle It

Why priority inversion occurs and the synchronization techniques used to mitigate it.

This English edition keeps the original illustrations and reproducible command or configuration examples.

Reference diagram 1

Commands and configuration

时间轴: T0      T1      T2      T3
-----------------------------------
任务A: |       |       |XXXXXXX|-------|
任务B: |-------|       |       |-------|
任务C: |       |-------|       |-------|
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

SemaphoreHandle_t xMutex;

void vTaskA(void *pvParameters) {
    for(;;) {
        // 尝试获取共享资源
        if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 访问共享资源
            // ...
            // 释放共享资源
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

void vTaskB(void *pvParameters) {
    for(;;) {
        // 获取共享资源
        if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 占用共享资源一段时间
            vTaskDelay(200);
            // 释放共享资源
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

void vTaskC(void *pvParameters) {
    for(;;) {
        // 中优先级任务执行
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}

int main(void) {
    xMutex = xSemaphoreCreateMutex();

    xTaskCreate(vTaskA, "Task A", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
    xTaskCreate(vTaskB, "Task B", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(vTaskC, "Task C", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

    vTaskStartScheduler();

    for(;;);
}
xMutex = xSemaphoreCreateMutex();
void lock(SemaphoreHandle_t xMutex) {
    uxOriginalPriority = uxTaskPriorityGet(NULL);
    vTaskPrioritySet(NULL, RESOURCE_PRIORITY_CEILING);
    xSemaphoreTake(xMutex, portMAX_DELAY);
}

void unlock(SemaphoreHandle_t xMutex) {
    xSemaphoreGive(xMutex);
    vTaskPrioritySet(NULL, uxOriginalPriority);
}

// 放入到共享资源部分
void vTaskB(void *pvParameters) {
    for(;;) {
        // 尝试获取共享资源
        lock(xMutex);
        // 访问共享资源
        // ...
        unlock(xMutex);
        vTaskDelay(100);
    }
}

Practical notes

Test each change on a recoverable target, keep logs from the boot or failure path, and record the exact kernel and userspace versions used in the result.