一、为什么要使用互斥量?
我们想让任务A、B都执行add_a函数,a的最终结果是1+8+8=17
。
假设任务A运行完代码①,在执行代码②之前被任务B抢占了:现在任务A的R0等于1。 任务B执行完add_a函数,a等于9。 任务A继续运行,在代码②处R0仍然是被抢占前的数值1,执行完②③的代码,a等于9,这跟预期的17不符合。 这样子我们就需要引入互斥量,来变量两个函数的冲突。
在接下来的互斥量特性一:互斥保护,可以解决这个问题。
互斥量也被称为互斥锁,使用过程如下:
- 互斥量初始值为1
- 任务A想访问临界资源,先获得并占有互斥量,然后开始访问
- 任务B也想访问临界资源,也要先获得互斥量:被别人占有了,于是阻塞
- 任务A使用完毕,释放互斥量;任务B被唤醒、得到并占有互斥量,然后开始访问临界资源
- 任务B使用完毕,释放互斥量
二、互斥量的创建和使用
1、创建
2、其他函数
三、互斥量的工作特性
互斥信号量的工作流程如下:
-
创建:使用 xSemaphoreCreateMutex() 创建互斥信号量,返回信号量句柄。
-
获取:任务通过 xSemaphoreTake(mutex, timeout) 获取信号量。如果信号量可用,任务获取并继续执行;如果被占用,任务阻塞直到信号量可用或超时。portMAX_DELAY 表示无限期等待。
-
释放:任务通过 xSemaphoreGive(mutex) 释放信号量,允许其他任务获取。
-
互斥性:一次只有一个任务可以持有信号量,其他任务必须等待。
特性一:互斥保护
假如任务A、B同时进行IIC操作,会造成IIC冲突,需要通过 GetI2C 和 PutI2C,g_xI2CMutex 确保 I2C 总线访问的互斥性,防止硬件冲突。
xSemaphoreTake:获得互斥量,上锁。
xSemaphoreGive:解锁互斥量,解锁。
特性二:不同优先级使用互斥量,会优先级继承
什么是优先级继承?
优先级继承是 FreeRTOS 互斥信号量的一个关键特性,用于避免 优先级反转。优先级反转是指高优先级任务因等待低优先级任务持有的资源而被阻塞,且可能被中优先级任务抢占,导致延迟。
工作机制
-
当高优先级任务尝试获取被低优先级任务持有的互斥信号量时,FreeRTOS 临时将低优先级任务的优先级提升到高优先级任务的水平。
-
低优先级任务以高优先级运行,尽快完成资源使用并释放信号量。
-
释放信号量后,低优先级任务的优先级恢复。
例子:
假设有三个任务:
-
Task L(低优先级,优先级 1)使用互斥量
-
Task M(中优先级,优先级 2)
-
Task H(高优先级,优先级 3)使用互斥量
-
Task H需要Task L互斥量的释放,才能获取互斥量,才能执行
流程如下:
-
Task L 获取互斥信号量,开始使用资源。
-
Task H 尝试获取信号量,但被 Task L 阻塞。
-
FreeRTOS 将 Task L 的优先级提升到 3(与 Task H 相同)。
-
Task L 继续运行,优先于 Task M,完成资源使用并释放信号量。(这样不会因为Task M的优先级比Task L高,一直执行,耽误Task L互斥量的释放)
-
Task L 优先级恢复到 1,Task H 获取信号量并运行。
这确保 Task H 不被 Task M 抢占,减少等待时间。
四、总结
互斥信号量是 FreeRTOS 中用于保护共享资源和协调任务的重要工具。它通过互斥访问和优先级继承确保系统安全和高效。