欢迎光临
我们一直在努力

为什么一定要用互斥量(Mutex)?别只怪共享资源,看看优先级继承

摘要:两个任务共享一个串口,为了防止打印乱码,用了全局变量做标志位(Flag)或二值信号量(Binary Semaphore),结果系统卡死了?不是任务逻辑错了,而是 优先级反转(Priority Inversion)。本文解析为什么必须用 Mutex。


一、问题描述(现象)

**任务 A(高优先级)要打印 Log;

任务 B(低优先级)正在打印 Log;

任务 A 等待任务 B 释放资源,但任务 B 被任务 C(中优先级)抢占了;

结果:任务 A 等不到任务 B,系统卡死。**

很多工程师的直觉是:

  • 加个 while(flag);自旋锁?

  • 关中断(Disable IRQ)?

  • 提高任务 B 的优先级?


  • 二、原理分析

    1. 物理模型

    三个任务,三个优先级。

    任务 A (High) -> 申请资源 -> 等待
    任务 B (Low) -> 占用资源 -> 被抢占
    任务 C (Middle)-> 运行 -> 不让 B 跑

    2. 核心参数

    • Binary Semaphore(二值信号量):只是一个“钥匙”,不管谁拿着钥匙,都不影响优先级。

    • Mutex(互斥量):带有 优先级继承(Priority Inheritance)​ 机制的锁。

    3. 反直觉真相

    “用 Binary Semaphore 保护共享资源是错的。”

    • 如果你用信号量:

      • 低优先级任务 B 拿到信号量。

      • 高优先级任务 A 申请信号量,失败,进入阻塞。

      • 中优先级任务 C 抢占了 B。

      • 结果:A 在等 B,B 在等 C,C 在跑。死锁。


    三、工程级解决方案

    方案 1:使用 Mutex 代替 Binary Semaphore(铁律)

    凡是保护共享资源的,一律用 Mutex。

    SemaphoreHandle_t xMutex;

    void Task_Init(void)
    {
    xMutex = xSemaphoreCreateMutex();
    }

    void Task_A(void *arg)
    {
    if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
    // 访问共享资源(如 UART)
    printf("Hello from Task A\\n");
    xSemaphoreGive(xMutex);
    }
    }

    方案 2:理解优先级继承

    当你使用 Mutex 时,发生了什么:

  • 任务 B(Low)拿到 Mutex。

  • 任务 A(High)申请 Mutex。

  • 系统自动把任务 B 的优先级提升到 High。

  • 任务 B 运行完,释放 Mutex,变回 Low。

  • 任务 A 获得 Mutex,运行。

  • 结果:中优先级任务 C 再也没有机会插队打断 B,死锁解除。

    方案 3:不要在中断里用 Mutex

    Mutex 不能在 ISR 里使用。

    • ISR 里只能用 Binary Semaphore​ 或 Direct to Task Notification。

    • 如果 ISR 也要访问共享资源,必须在 ISR 中释放信号量,由任务去拿 Mutex。


    四、选型避坑建议

  • 不要递归拿锁:

    • 同一个任务连续两次 xSemaphoreTake(Mutex),会导致死锁(除非是 Recursive Mutex)。

  • 持锁时间越短越好:

    • 拿锁 -> 操作 -> 放锁,中间不要有 vTaskDelay。

  • 死锁预防:

    • 如果多个资源,规定获取锁的顺序(如先拿 A 再拿 B)。


  • 五、总结 Checklist

    • [ ] 保护共享资源用的是 Mutex 还是 Binary Semaphore?

    • [ ] 是否理解 Mutex 的优先级继承机制?

    • [ ] 是否在 ISR 里错误地使用了 Mutex?

    • [ ] 持锁的代码里是否有延时或阻塞操作?


    六、写在最后(关注我,少走弯路)

    我是 gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。

    如果说栈溢出是 RTOS 的“急性病”,那么优先级反转就是“慢性病”。不用 Mutex,系统迟早会卡死在某个不可复现的时刻。

    关注我的专栏《嵌入式底层避坑指南》,下一篇我们将深入解析 《临界区(Critical Section)卡死?别只怪关中断,看看中断嵌套》。

    👉 下一篇预告:《临界区(Critical Section)卡死?别只怪关中断,看看中断嵌套》


    原创文章,转载请注明出处。

    赞(0)
    未经允许不得转载:171主机测评 » 为什么一定要用互斥量(Mutex)?别只怪共享资源,看看优先级继承
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址