是一种特殊的二值信号量。
特殊点:支持互斥量的所有权 实现_互斥量 - 图1

优先级继承机制

:::info 某个临界资源受到一个互斥量保护,如果这个资源正在被一个低优先级任务使用,那么此时的互斥量是闭锁状态,也代表了没有任务能申请到这个互斥量,如果此时一个高优先级任务想要对这个资源进行访问,去申请这个互斥量,那么高优先级任务会因为申请不到互斥量而进入阻塞态,那么系统会将现在持有该互斥量的任务的优先级临时提升到与高优先级任务的优先级相同,这个优先级提升的过程叫做优先级继承。
:::

场景

现在有 3 个任务分别为
H 任务(High)、M 任务(Middle)、L 任务 (Low),

3 个任务的优先级顺序为 H 任务>M 任务>L 任务。

正常运行的时候 H 任务可以打断 M 任务与 L 任务,M 任务可以打断 L 任务

假设系统中有一个资源被保护了,此时该资源被 L 任务正在使用中,某一刻,H 任务需要使用该资源,但是 L 任务还没使用完,H 任务则因为申请不到资源而进入阻塞态,L 任务继续使用该资源,此时已经出现了“优先级翻转”现象,高优先级任务在等着低优先级的任务执行,如果在 L 任务执行的时候刚好 M 任务被唤醒了,由于 M 任务优先级比 L 任务优先级高,那么会打断 L 任务,抢占了 CPU 的使用权,直到 M 任务执行完,再把 CUP 使用权归还给 L 任务,L 任务继续执行,等到执行完毕之后释放该资源,H 任务此时才从阻塞态解除,使用该资源。

互斥量运作机制

多任务环境下会存在多个任务访问同一临界资源的场景,该资源会被任务独占处理。
其他任务在资源被占用的情况下不允许对该临界资源进行访问,这个时候就需要用到FreeRTOS 的互斥量来进行资源保护,那么互斥量是怎样来避免这种冲突?

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

image.png

互斥量控制块

image.png
(1): pcReadFrom 与 uxRecursiveCallCount 是一对互斥变量,使用联合 体用来确保两个互斥的结构体成员不会同时出现。当结构体用于队列时,pcReadFrom 指向 出队消息空间的最后一个,见文知义,就是读取消息时候是从 pcReadFrom 指向的空间读 取消息内容。当结构体用于互斥量时,uxRecursiveCallCount 用于计数,记录递归互斥量被“调用”的次数。

(2):如果控制块结构体是用于消息队列:uxMessagesWaiting 用来记录 当前消息队列的消息个数;如果控制块结构体被用于互斥量的时候,这个值就表示有效互斥量个数,这个值是 1 则表示互斥量有效,如果是 0 则表示互斥量无效。

(3):如果控制块结构体是用于消息队列:uxLength表示队列的长度,也就是能存放多少消息;如果控制块结构体被用于互斥量的时候,uxLength 表示最大的信 号量可用个数,uxLength 最大为 1,因为信号量要么是有效的,要么是无效的。

(4):如果控制块结构体是用于消息队列:uxItemSize 表示单个消息的大小;如果控制块结构体被用于互斥量的时候,则无需存储空间,为 0 即可。


函数接口

实现_互斥量 - 图4