FreeRTOS 中的互斥信号量(Mutex Semaphore)是一种特殊的二值信号量,专为解决资源互斥访问和优先级反转问题设计。其核心特性是支持优先级继承(Priority Inheritance),当高优先级任务因等待低优先级任务持有的互斥量而阻塞时,低优先级任务会临时继承高优先级任务的优先级。以下是互斥信号量相关的 API 函数详解,包括动态和静态创建两种方式。
1. 动态创建互斥信号量
函数原型
SemaphoreHandle_t xSemaphoreCreateMutex(void);
- 功能:动态分配内存并初始化一个互斥信号量。
- 参数:无。
- 返回值:
- 成功:返回互斥量句柄(
SemaphoreHandle_t
)。 - 失败:返回
NULL
(内存不足时)。
- 成功:返回互斥量句柄(
- 特点:
- 初始状态为 可用(计数值为 1,可直接获取)。
- 需确保 FreeRTOS 堆内存足够(通过
configTOTAL_HEAP_SIZE
配置)。 - 支持优先级继承(需配置
configUSE_MUTEXES = 1
)。
示例代码
SemaphoreHandle_t xMutex = NULL;
void vTaskExample(void) {
// 动态创建互斥信号量
xMutex = xSemaphoreCreateMutex();
if (xMutex != NULL) {
// 创建成功
}
}
2. 静态创建互斥信号量
函数原型
SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer);
- 功能:使用用户预先分配的静态内存初始化互斥信号量。
- 参数:
pxMutexBuffer
:指向StaticSemaphore_t
类型变量的指针,用于存储互斥量内部数据。
- 返回值:
- 成功:返回互斥量句柄。
- 失败:返回
NULL
(参数无效时)。
- 特点:
- 初始状态为 可用。
- 需预先分配
StaticSemaphore_t
结构体内存(全局或静态变量)。
示例代码
StaticSemaphore_t xMutexBuffer;
SemaphoreHandle_t xMutex = NULL;
void vTaskExample(void) {
// 静态创建互斥信号量
xMutex = xSemaphoreCreateMutexStatic(&xMutexBuffer);
if (xMutex != NULL) {
// 创建成功
}
}
3. 获取(Take)互斥量
函数原型
BaseType_t xSemaphoreTake(
SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait // 阻塞时间
);
- 功能:尝试获取互斥量。若已被占用,任务将阻塞等待。
- 参数:
xSemaphore
:互斥量句柄。xTicksToWait
:阻塞时间(单位:系统节拍)。portMAX_DELAY
表示无限等待(需配置INCLUDE_vTaskSuspend=1
)。
- 返回值:
pdTRUE
:成功获取互斥量。pdFALSE
:超时或参数无效。
- 关键规则:
- 必须由获取互斥量的任务释放互斥量(不可跨任务释放)。
4. 释放(Give)互斥量
函数原型
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
- 功能:释放互斥量,允许其他任务获取。
- 参数:
xSemaphore
:互斥量句柄。
- 返回值:
pdPASS
:释放成功。pdFAIL
:释放失败(当前任务未持有该互斥量)。
- 注意:
- 必须由持有互斥量的任务调用此函数。
5. 删除互斥量
函数原型
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);
- 功能:删除互斥量并释放内存(仅对动态创建的互斥量有效)。
- 参数:
xSemaphore
:互斥量句柄。
- 注意:
- 删除前需确保无任务持有该互斥量,否则可能导致未定义行为。
使用场景示例
保护共享资源
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
// 任务 A 访问共享资源
void vTaskA(void *pvParameters) {
while (1) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 安全访问共享资源
// ...
xSemaphoreGive(xMutex); // 释放互斥量
}
vTaskDelay(10);
}
}
// 任务 B 访问共享资源
void vTaskB(void *pvParameters) {
while (1) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 安全访问共享资源
// ...
xSemaphoreGive(xMutex); // 释放互斥量
}
vTaskDelay(10);
}
}
注意事项
-
优先级继承:
- 互斥量自动启用优先级继承,无需额外配置(需
configUSE_MUTEXES = 1
)。 - 当高优先级任务等待低优先级任务释放互斥量时,低优先级任务会临时继承高优先级任务的优先级。
- 互斥量自动启用优先级继承,无需额外配置(需
-
不可跨任务释放:
- 必须由获取互斥量的任务释放,否则会导致
xSemaphoreGive
返回pdFAIL
。
- 必须由获取互斥量的任务释放,否则会导致
-
递归互斥量:
- 若任务需多次获取同一互斥量,应使用递归互斥量(
xSemaphoreCreateRecursiveMutex()
),并通过xSemaphoreTakeRecursive()
和xSemaphoreGiveRecursive()
操作。
- 若任务需多次获取同一互斥量,应使用递归互斥量(
-
中断中不可使用:
- 互斥量不能在中断服务程序(ISR)中获取或释放(无
FromISR
版本)。
- 互斥量不能在中断服务程序(ISR)中获取或释放(无
-
死锁风险:
- 避免同一任务多次获取互斥量(除非使用递归互斥量)。
- 确保互斥量释放逻辑在所有代码路径中执行(如使用
goto
或return
前释放)。
互斥量 vs 二值信号量
特性 | 互斥量 | 二值信号量 |
---|---|---|
初始值 | 1(可用) | 0(不可用) |
释放者 | 必须由获取者释放 | 任意任务或中断均可释放 |
优先级继承 | 支持 | 不支持 |
适用场景 | 保护共享资源,防止优先级反转 | 任务同步或简单事件通知 |
通过合理使用互斥信号量,可确保共享资源的安全访问,避免数据竞争和优先级反转问题。