递归信号量
一、概述
互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。在初始化的时候,互斥量处于开锁的状态,而被任务持有的时候则立刻转为闭锁的状态。
递归类型的互斥量可以被拥有者重复获取。拥有互斥量的任务必须调用API函数xSemaphoreGiveRecursive()将拥有的递归互斥量全部释放后,该信号量才真正被释放。比如,一个任务成功获取同一个互斥量5次,那么这个任务要将这个互斥量释放5次之后,其它任务才能获取到它。递归互斥信号量,其实就是互斥信号量里面嵌套互斥信号量,示例如下:
static void vTaskMsgPro(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 1500;
/* 获取当前的系统时间 */
xLastWakeTime = xTaskGetTickCount();
while(1)
{
/* 递归互斥信号量,其实就是互斥信号量里面嵌套互斥信号量 */
xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
{
/* -------------------------------------- */
//假如这里是被保护的资源,第1层被保护的资源,用户可以在这里添加被保护资源
/* ---------------------------------------------------------------------------- */
printf("任务vTaskMsgPro在运行,第1层被保护的资源,用户可以在这里添加被保护资源\r\n");
/* 第1层被保护的资源里面嵌套被保护的资源 */
xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
{
/* ------------------------------------------------------------------------ */
//假如这里是被保护的资源,第2层被保护的资源,用户可以在这里添加被保护资源
/* ------------------------------------------------------------------------ */
printf("任务vTaskMsgPro在运行,第2层被保护的资源,用户可以在这里添加被保护资源\r\n");
/* 第2层被保护的资源里面嵌套被保护的资源 */
xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
{
printf("任务vTaskMsgPro在运行,第3层被保护的资源,用户可以在这里添加被保护资源\r\n");
}
xSemaphoreGiveRecursive(xRecursiveMutex);
}
xSemaphoreGiveRecursive(xRecursiveMutex);
}
xSemaphoreGiveRecursive(xRecursiveMutex);
/* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
二、配置
使能递归互斥量,详细文件在FreeRTOS.h。
文件路径:FreeRTOS.h
#ifndef configUSE_RECURSIVE_MUTEXES
#define configUSE_RECURSIVE_MUTEXES 1
#endif
三、函数接口
1.创建递归互斥量
#if((configSUPPORT_DYNAMIC_ALLOCATION==1) && (configUSE_RECURSIVE_MUTEXES ==1))
#define xSemaphoreCreateRecursiveMutex()
xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
#endif
参数:无
返回值:
如果创建成功则返回一个递归互斥量句柄,用于访问创建的递归互斥量。如果创建不成功则返回 NULL。
2.获取递归互斥量
#if( configUSE_RECURSIVE_MUTEXES == 1 )
#define xSemaphoreTakeRecursive( xMutex, xBlockTime )
xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
#endif
参数:
- tick(即系统节拍周期)。如果
宏 INCLUDE_vTaskSuspend 定义为 1 且形参 xTicksToWait 设置为portMAX_DELAY ,则任务将一直阻塞在该递归互斥量上(即没有超时时间)。
返回值:
获取成功则返回 pdTRUE,在超时之前没有获取成功则返回 errQUEUE_EMPTY。
3.释放递归互斥量
#if( configUSE_RECURSIVE_MUTEXES == 1 )
#define xSemaphoreGiveRecursive( xMutex ) \
xQueueGiveMutexRecursive( ( xMutex ) )
#endif
参数:
返回值:
成功,pdPASS
失败,pdFAIL
四、示例代码
1.freertos.c
static void app_task1(void* pvParameters)
{
for(;;)
{
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task1 is running 1...\r\n");
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task1 is running 2...\r\n");
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task1 is running 3...\r\n");
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
vTaskDelay(300);
}
}
static void app_task2(void* pvParameters)
{
for(;;)
{
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task2 is running 1...\r\n");
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task2 is running 2...\r\n");
//
获取递归互斥信号量
xSemaphoreTakeRecursive(MutexSemaphore, portMAX_DELAY);
{
printf("app_task2 is running 3...\r\n");
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
}
//
释放递归互斥信号量
xSemaphoreGiveRecursive(MutexSemaphore);
vTaskDelay(200);
}
}
演示