🍎引入
在FreeRTOS中,互斥量是一种用于保护共享资源的同步机制。它通过二进制信号量的方式,确保在任意时刻只有一个任务可以获取互斥量并访问共享资源,其他任务将被阻塞。使用互斥量的基本步骤包括创建互斥量、获取互斥量、访问共享资源和释放互斥量。互斥量在FreeRTOS中起到了重要的作用,保护共享资源的访问,提供了一种有效的同步机制,确保任务之间的协作和数据的一致性。
换句话说就是使用互斥量解决双线程之间数据耦合的问题,而互斥量(Mutex)是一种用于保护临界资源的同步机制,通过独占式访问确保多任务环境下数据的一致性和安全性。
🍐内部原理
-
独占访问控制 互斥量通过“谁持有,谁释放”的机制,确保同一时刻仅有一个任务能访问临界资源。当任务A获取互斥量后,其他任务必须等待其释放才能继续操作。按照韦东山老师的话来说,就是谁抢占就干掉谁,在获取互斥量之后,会在底层关闭相应的任务调度或者是中断访问,以确保互斥量task获取到cpu资源
-
优先级继承机制 当高优先级任务因低优先级任务持有互斥量而阻塞时,系统会临时提升低优先级任务的优先级至高优先级任务的同级,避免优先级反转问题(如任务H等待任务L释放资源时,任务M抢占L导致H长时间阻塞)
-
递归互斥量支持 递归互斥量允许同一任务多次获取锁(需对应次数的释放),适用于需要重复访问临界资源的场景,但需注意避免死锁
🍌互斥量的使用
需要注意的是互斥量不能在中断服务函数(ISR)中使用,需改用信号量或直接屏蔽中断,然后是使用后需要即使释放避免死锁出现
-
创建互斥量
-
动态创建:
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
需先在
FreeRTOSConfig.h
中启用configSUPPORT_DYNAMIC_ALLOCATION
,当然你也可以在stm32cubemx上配置简单快捷 -
静态创建:
StaticQueue_t xStaticMutex; SemaphoreHandle_t xMutex = xSemaphoreCreateMutexStatic(&xStaticMutex);
需预先分配静态内存并启用
configSUPPORT_STATIC_ALLOCATION
,中间件的配置同上,建议在cubemx上进行配置,因为使用cubemx创建的项目在重新生成时会初始化自定义的中间件配置
-
获取与释放互斥量
-
获取互斥量:
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { // 访问临界资源 }
portMAX_DELAY
表示无限等待,也可设置超时时间 -
释放互斥量:
xSemaphoreGive(xMutex);
仅持有者可释放,否则可能导致死锁
-
删除互斥量
vSemaphoreDelete(xMutex);
🍒互斥量对临界资源的保护
在访问共享资源(如全局变量、外设)前加锁,确保操作的原子性。通过优先级继承机制,临时提升低优先级任务的优先级,减少高优先级任务阻塞时间
void Task1(void *pvParameters) {
xSemaphoreTake(xMutex, portMAX_DELAY);
sharedCounter++; // 临界区操作
xSemaphoreGive(xMutex);
}
若任务需多次访问同一资源,使用递归互斥量(xSemaphoreCreateRecursiveMutex
)避免自锁问题。另外临界区代码应尽量简短,避免长时间占用互斥量导致系统实时性下降,如出现占用cpu资源进行长时间的SPI通信
🍅与二值信号量对比
在FreeRTOS中,互斥量(Mutex)和二值信号量(Binary Semaphore)均基于二值状态(0或1)实现任务同步,但它们的设计目标、功能特性及适用场景存在显著差异
本质:互斥量是二值信号量的plus版 互斥量本质上是具有优先级继承机制和所有权管理的特殊二值信号量。其底层实现通常基于队列(FreeRTOS通过xQueueCreateMutex()
创建),但通过额外机制优化了互斥场景下的任务调度。而反观二值信号量,仅用于任务或中断间的同步(如事件通知),不涉及资源所有权管理,也无法解决优先级反转问题
当高优先级任务因低优先级任务持有互斥量而阻塞时,系统会临时提升低优先级任务的优先级至高优先级任务的同级,避免中间优先级任务抢占,从而减少阻塞时间,很好的解决了信号量出现的优先级反转问题
🍅优先级反转问题
在FreeRTOS中,二值信号量(Binary Semaphore)本身并不直接支持优先级继承机制,因此在使用信号量进行任务同步时,可能发生优先级反转问题。这一问题与互斥量(Mutex)的场景类似,但信号量缺乏内置的优先级继承机制,导致其风险更高。
举个例子就是,当24和26优先级的任务同时使用一个信号量,而24的优先级先执行,然后碰到25优先级的任务出来抢占cpu资源一直运行,而此时26优先级的任务想来执行发现没有信号量被阻塞,这就是优先级反转
🍈总结
互斥量就是一种特殊的信号量,解决了信号量优先级反转的问题,同时实现对临界资源的互斥访问