1.开发背景
基于上一个篇章,解释了 FreeRTOS 的互斥锁,可以看出互斥锁是可以保护资源访问的完整性,但是,随着代码的复杂程度提高,有可能存在代码段递归的情况,这样就有可能会出现多次上锁的情况,而 FreeRTOS 提供了递归上锁的操作,即一个锁可以在一个线程中多次上锁,只有解锁同等次数才能真正解锁。
实际上,递归互斥锁是互斥锁的一种特殊形态,类似计数信号量和二值信号量的关系,当然,递归互斥锁拥有和互斥锁相同的特性,那就是优先级继承。
2.开发需求
设计实验:
1)创建 2 个线程
2)其中一个线程多次上锁后解锁同等次数
3)另一个线程等待多次解锁完成
3.开发环境
window10 + MDK + STM32F429 + FreeRTOS10.3.1
4.实现步骤
4.1 实现编码
#include "appTest.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mspDwt.h"
#include "mspGpio.h"
#include "mspExti.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "appLog.h"
typedef struct
{
/* 信号量 */
SemaphoreHandle_t lock; // 信号锁
/* 创建任务 */
TaskHandle_t taskCtrl;
TaskHandle_t taskLow; // 低优先级线程
TaskHandle_t taskHigh; // 高优先级线程
}Ctrl_t;
/* 文件指针 */
static Ctrl_t s_ctrl = {0};
static Ctrl_t *p = &s_ctrl;
static void TaskCtrl(void *pvParameters);
static void TaskLow(void *pvParameters);
static void TaskHigh(void *pvParameters);
static void TaskCtrl(void *pvParameters)
{
for ( ; ; )
{
vTaskDelay(1000);
}
}
/* 接收线程 */
static void TaskLow(void *pvParameters)
{
vTaskDelay(100);
for ( ; ; )
{
Log_Debug("%s 准备取锁\r\n", __func__);
xSemaphoreTakeRecursive(p->lock, portMAX_DELAY);
Log_Debug("%s 获取到递归锁\r\n", __func__);
vTaskDelay(1000);
xSemaphoreGiveRecursive(p->lock);
}
}
/* 发送线程 */
static void TaskHigh(void *pvParameters)
{
vTaskDelay(100);
#define COUNT_MAX_NUM (5)
int count = 1;
for ( ; ; )
{
xSemaphoreTakeRecursive(p->lock, portMAX_DELAY);
Log_Debug("%s 获取到递归锁[%d]\r\n", __func__, count);
if (count < COUNT_MAX_NUM)
{
vTaskDelay(1000);
count++;
continue;
}
/* 释放所有已获取的锁 */
while (count > 0)
{
Log_Debug("%s 释放递归锁[%d]\r\n", __func__, count);
xSemaphoreGiveRecursive(p->lock);
vTaskDelay(1000);
count--;
}
/* 挂起线程自身 */
vTaskSuspend(NULL);
}
}
/* 测试初始化 */
void aTest_Init(void)
{
/* 创建信号锁 */
p->lock = xSemaphoreCreateRecursiveMutex();
/* 创建动态任务 */
xTaskCreate(TaskCtrl, "TaskCtrl", 500, NULL, 4, &p->taskCtrl);
xTaskCreate(TaskLow, "TaskLow", 500, NULL, 4, &p->taskLow);
xTaskCreate(TaskHigh, "TaskHigh", 500, NULL, 5, &p->taskHigh);
}
/* Key2 PC13 Key0 PH3 Key1 PH2 */
void Exti13_TriggerInterrupt(void)
{
mspExti_Close(13);
if (mspGpio_GetInput("PC13") == 0)
{
}
}