互斥量即互斥信号量,是特殊的二值信号量,比二值信号量多了一个优先级继承,它与信号量不同的是,它支持互斥量所有权、递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理。
任何时刻互斥量的状态只有两种:开锁和闭锁。
当互斥量被任务持有时,该互斥量处于闭锁状态,这个任务获得互斥量的所有权。释放互斥量时,则处于开锁状态。
当一个任务持有互斥量时,其他任务不能再对该互斥量进行开锁或持有。持有该互斥量的任务也能够再次获得这个锁而不被挂起,即递归访问。
实行同步二值信号量是最好的选择,互斥量更多的是用于保护资源的互锁。
如何理解互斥量的使用场景:(互斥量也被称为互斥锁)
1)互斥量初始值为 1
2)任务 A 想访问临界资源,先获得并占有互斥量,然后开始访问
3)任务 B 也想访问临界资源,也要先获得互斥量:被别人占有了,于是阻塞
4)任务 A 使用完毕,释放互斥量;任务 B 被唤醒、得到并占有互斥量,然后开始访问临界资源
5)任务 B 使用完毕,释放互斥量
正常来说:在任务 A 占有互斥量的过程中,任务 B、任务 C 等等,都无法释放互斥量。但是 FreeRTOS 未实现这点:任务 A 占有互斥量的情况下,任务 B 也可释放互斥量。
优先级继承:
即当低优先级的任务获取了互斥量还没释放时,一个高优先级的任务也想获取互斥量,此时高优先级的任务会获取互斥量失败,当它愿意等待互斥量时会将低优先级的任务的优先级暂时提高到和自己的一样,直到其释放互斥量的时候再恢复其原来的优先级并换唤醒刚等待互斥量的任务。(借助下图理解)
/* 创建一个互斥量,返回它的句柄。
* 此函数内部会分配互斥量结构体
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateMutex( void );
/* 创建一个互斥量,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个 StaticSemaphore_t 结构体,并传入它的指
针
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );
xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量
*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
/* 释放 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
/* 释放(ISR 版本) */
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphoreBaseType_t *pxHigherPriorityTaskWoken);
/* 获得 */
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait);
/* 获得(ISR 版本) */
xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
递归锁解决了FreeRTOS中开关锁的缺陷,即实现了谁上锁就由谁解锁