从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十四)互斥量 NO.1 基本概念

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十四)互斥量 NO.1 基本概念

一、互斥量基本概念:

① 互斥量又称互斥信号量(本质是信号量),是一种特殊的二值信号量,它和信号量不同的是,它支持互斥量所有权递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理

② 用于互锁的互斥量可以充当保护资源的令牌,当一个任务希望访问某个资源时,它必须先获取令牌。当任务使用完资源后,必须还回令牌,以便其它任务可以访问该资源

③ 一个任务持有互斥量时,其他任务将不能再对该互斥量进行开锁或持有。 持有该互斥量的任务也能够再次获得这个锁而不被挂起,这就是递归访问,也就是递归互斥量的特性。

二、互斥量的优先级继承机制:

① 信号量会导致的另一个潜在问题,那就是任务优先级翻转。FreeRTOS提供的互斥量可以通过优先级继承算法可以降低优先级翻转问题产生的影响,所以,用于临界资源的保护一般建议使用互斥量

什么是优先级翻转呢?我们知道任务的优先级在创建的时候就已经是设置好的,高优先级的任务可以打断低优先级的任务,抢占CPU的使用权。但是在很多场合中,某些资源只有一个,当低优先级任务正在占用该资源的时候,即便优先级任务也只能乖乖的等待低优先级任务使用完该资源后释放资源。这里高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”

③ 互斥量与二值信号量最大的不同是:互斥量具有优先级继承机制,而信号量没有。也就是说,某个临界资源受到一个互斥量保护,如果这个资源正在被一个低优先级任务使用,那么此时的互斥量是闭锁状态,也代表了没有任务能获取到这个互斥量,如果此时一个高优先级任务想要对这个资源进行访问,去获取这个互斥量,那么高优先级任务会因为获取不到互斥量而进入阻塞态,那么系统会将现在持有该互斥量的任务的优先级临时提升到与高优先级任务的优先级相同,这个优先级提升的过程叫做优先级继承。这个优先级继承机制确保高优先级任务进入阻塞状态的时间尽可能短,以及将已经出现的“优先级翻转”危害降低到最小。

因此,继承优先级的任务避免了系统资源被任何中间优先级的任务抢占

三、互斥量应用场景:

        互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。在初始化的时候,互斥量处于开锁的状态,而被任务持有的时候则立刻转为闭锁的状态

互斥量更适合于

可能会引起优先级翻转的情况

递归互斥量更适用于:

任务可能会多次获取互斥量的情况下。这样可以避免同一任务多次递归持有而造成死锁的问题

另外需要注意的是互斥量不能在中断服务函数中使用,因为其特有的优先级继承机制只在任务起作用,在中断的上下文环境毫无意义

四、互斥量运作机制:

       用互斥量处理不同任务对临界资源的同步访问时,任务想要获得互斥量才能进行资源访问,如果一旦有任务成功获得了互斥量,则互斥量立即变为闭锁状态,此时其他任务会因为获取不到互斥量而不能访问这个资源,任务会根据用户自定义的等待时间进行等待,直到互斥量被持有的任务释放后,其他任务才能获取互斥量从而得以访问该临界资源,此时互斥量再次上锁,如此一来就可以确保每个时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的安全性。见下图(来自野火论坛)

(1):因为互斥量具有优先级继承机制,一般选择使用互斥量对资源进行保护,如果资源被占用的时候,无论是什么优先级的任务想要使用该资源都会被阻塞。
(2):假如正在使用该资源的任务 1 比阻塞中的任务 2 的优先级还低,那么任务1 将被系统临时提升到与高优先级任务 2 相等的优先级(任务 1 的优先级从 L 变成 H)。
(3):当任务 1 使用完资源之后,释放互斥量,此时任务 1 的优先级会从 H 变回原来的 L。
(4)-(5): 任务 2 此时可以获得互斥量,然后进行资源的访问,当任务 2 访问了资源的时候,该互斥量的状态又为闭锁状态,其他任务无法获取互斥量。

五、互斥量控制块:

        互斥量的 API 函数实际上都是宏,它使用现有的队列机制, 这些宏定义在 semphr.h 文件中, 如果使用互斥量,需要包含 semphr.h 头文件。 

  union                             
  {
        int8_t *pcReadFrom;        
        UBaseType_t uxRecursiveCallCount
    } u;

    volatile UBaseType_t uxMessagesWaiting

    UBaseType_t uxLength;           

    UBaseType_t uxItemSize;        

(1): pcReadFrom 与 uxRecursiveCallCount 是一对互斥变量, 使用联合体用来确保两个互斥的结构体成员不会同时出现。 当结构体用于队列时, pcReadFrom 指向出队消息空间的最后一个,见文知义,就是读取消息时候是从 pcReadFrom 指向的空间读取消息内容。 当结构体用于互斥量时, uxRecursiveCallCount 用于计数,记录递归互斥量被“调用” 的次数。
(2):如果控制块结构体是用于消息队列 uxMessagesWaiting 用来记录当前消息队列的消息个数; 如果控制块结构体被用于互斥量的时候, 这个值就表示有效互斥量个数,这个值是 1 则表示互斥量有效,如果是 0 则表示互斥量无效。
(3): 如果控制块结构体是用于消息队列 uxLength 表示队列的长度,也就是能存放多少消息; 如果控制块结构体被用于互斥量的时候, uxLength 表示最大的信号量可用个数, uxLength 最大为 1,因为信号量要么是有效的,要么是无效的。
(4): 如果控制块结构体是用于消息队列uxItemSize 表示单个消息的大小; 如果控制块结构体被用于互斥量的时候, 则无需存储空间,为 0 即可。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值