首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >互斥量与二进制信号量:区别及相关概念解析(建议收藏!!!)

互斥量与二进制信号量:区别及相关概念解析(建议收藏!!!)

作者头像
紫昭
发布2025-11-29 08:10:29
发布2025-11-29 08:10:29
1620
举报

一、引言

在多任务并发编程中,互斥量(Mutex)和二进制信号量(Binary Semaphore)是常用的同步原语。它们在功能上有一些相似之处,但也存在明显的区别,其中在 FreeRTOS 中,互斥量通过 “优先级继承” 来解决 “优先级反转” 问题,而二进制信号量则不具备此特性。本文将详细探讨互斥量与二进制信号量的区别,并深入解析优先级反转和优先级继承的概念,通过代码示例帮助读者更好地理解。

二、互斥量与二进制信号量的基本概念

(一)二进制信号量

二进制信号量本质上是一种特殊的信号量,其计数值只能为 0 或 1。它主要用于实现任务之间或任务与中断之间的同步。例如,一个任务可以等待一个二进制信号量,当信号量被释放(设置为 1)时,等待的任务被唤醒并继续执行。

(二)互斥量

互斥量用于保护共享资源,确保在同一时刻只有一个任务能够访问该资源。当一个任务获取互斥量时,其他任务如果试图获取相同的互斥量将被阻塞,直到持有互斥量的任务释放它。

三、优先级反转

(一)概念

优先级反转是指在基于优先级可抢占调度系统中,低优先级任务持有一个高优先级任务所需的共享资源,导致高优先级任务被阻塞,而此时中优先级任务却能够抢占低优先级任务执行的现象。这违背了高优先级任务应该优先执行的原则,可能会导致系统的实时性得不到保障。

(二)代码示例

假设我们有三个任务:高优先级任务 Task_High、中优先级任务 Task_Medium 和低优先级任务 Task_Low,以及一个共享资源 Shared_Resource,由互斥量 mutex 保护。

代码语言:javascript
复制
// 共享资源
int Shared_Resource = 0;
// 互斥量
osMutexId_t mutex;

// 低优先级任务
void Task_Low(void *argument)
{
    // 获取互斥量
    osMutexWait(mutex, osWaitForever);
    // 模拟低优先级任务使用共享资源,耗时操作
    for (int i = 0; i < 10000; i++)
    {
        Shared_Resource++;
    }
    // 释放互斥量
    osMutexRelease(mutex);
    while (1)
    {
        // 低优先级任务的其他操作
        osDelay(1000);
    }
}

// 中优先级任务
void Task_Medium(void *argument)
{
    while (1)
    {
        // 中优先级任务的操作,可能会抢占低优先级任务
        osDelay(500);
    }
}

// 高优先级任务
void Task_High(void *argument)
{
    // 尝试获取互斥量,由于低优先级任务持有互斥量,高优先级任务被阻塞
    osMutexWait(mutex, osWaitForever);
    // 高优先级任务使用共享资源的操作
    Shared_Resource += 100;
    // 释放互斥量
    osMutexRelease(mutex);
    while (1)
    {
        // 高优先级任务的其他操作
        osDelay(100);
    }
}

在上述代码中,Task_Low 先获取了互斥量并开始操作共享资源。在其操作过程中,Task_High 被调度运行,由于需要获取被 Task_Low 持有的互斥量,Task_High 被阻塞。此时,Task_Medium 由于其优先级高于 Task_Low,可以抢占 Task_Low 执行,导致 Task_High 等待的时间变长,出现了优先级反转现象。

四、优先级继承

(一)概念

优先级继承是解决优先级反转问题的一种策略。当高优先级任务因低优先级任务持有互斥量而被阻塞时,系统将低优先级任务的优先级提升到与高优先级任务相同(或稍高)的优先级,直到低优先级任务释放互斥量。这样可以避免中优先级任务抢占低优先级任务,保证高优先级任务能够尽快获取到互斥量并执行。

(二)代码示例

在支持优先级继承的 FreeRTOS 环境中,对上述代码进行修改:

代码语言:javascript
复制
// 共享资源
int Shared_Resource = 0;
// 互斥量,设置为支持优先级继承
osMutexId_t mutex;

// 低优先级任务
void Task_Low(void *argument)
{
    // 获取互斥量,此时若高优先级任务需要该互斥量,低优先级任务优先级将提升
    osMutexWait(mutex, osWaitForever);
    // 模拟低优先级任务使用共享资源,耗时操作
    for (int i = 0; i < 10000; i++)
    {
        Shared_Resource++;
    }
    // 释放互斥量,低优先级任务优先级恢复
    osMutexRelease(mutex);
    while (1)
    {
        // 低优先级任务的其他操作
        osDelay(1000);
    }
}

// 中优先级任务
void Task_Medium(void *argument)
{
    while (1)
    {
        // 中优先级任务的操作,由于低优先级任务优先级提升,无法抢占
        osDelay(500);
    }
}

// 高优先级任务
void Task_High(void *argument)
{
    // 尝试获取互斥量,若低优先级任务持有,低优先级任务优先级提升后,高优先级任务等待
    osMutexWait(mutex, osWaitForever);
    // 高优先级任务使用共享资源的操作
    Shared_Resource += 100;
    // 释放互斥量
    osMutexRelease(mutex);
    while (1)
    {
        // 高优先级任务的其他操作
        osDelay(100);
    }
}

在这个修改后的代码中,当 Task_High 尝试获取被 Task_Low 持有的互斥量时,Task_Low 的优先级会被提升,Task_Medium 就无法抢占 Task_Low 的执行,从而减少了 Task_High 的阻塞时间,有效解决了优先级反转问题。

五、互斥量与二进制信号量在优先级反转处理上的区别

如前面所述,互斥量在 FreeRTOS 中通过优先级继承机制来应对优先级反转,而二进制信号量没有这种机制。在使用二进制信号量保护共享资源时,如果出现类似优先级反转的情况,高优先级任务只能等待低优先级任务释放信号量,期间可能会被中优先级任务长时间抢占,导致系统的实时性下降。

六、结论

互斥量和二进制信号量在多任务编程中都有着重要的作用,但它们在处理优先级反转问题上存在差异。理解优先级反转和优先级继承的概念,以及互斥量和二进制信号量的区别,对于开发可靠的多任务实时系统至关重要。在实际应用中,应根据系统的需求和特点,合理选择使用互斥量或二进制信号量,以确保系统的稳定性、可靠性和实时性。

“学如逆水行舟,不进则退。”愿此篇文章成为你在技术之舟上的有力浆橹。有任何感悟或困惑,可于评论区交流探讨。若觉有益,点赞,收藏不妨一试,也期待你关注我。在技术的漫漫征途中,愿与君相伴而行,共赏知识繁花盛景,同历成长蜕变之喜。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引言
    • 二、互斥量与二进制信号量的基本概念
      • (一)二进制信号量
      • (二)互斥量
    • 三、优先级反转
      • (一)概念
      • (二)代码示例
    • 四、优先级继承
      • (一)概念
      • (二)代码示例
    • 五、互斥量与二进制信号量在优先级反转处理上的区别
    • 六、结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档