当前位置: 首页 > ops >正文

【freertos互斥量补充】递归锁

一、什么是递归(recursive)锁

递归锁(Recursive Mutex)是互斥量的 “增强版”,允许同一任务多次获取同一把锁,且不会因重复申请导致死锁。解锁时需 “配对释放”(获取多少次,就要释放多少次)。

  • 普通互斥量(Mutex)
    同一任务若已持有锁,再次调用 xSemaphoreTake() 会立即阻塞(自己等自己,导致死锁)。

  • 递归锁(Recursive Mutex)
    同一任务可多次获取锁(内部通过计数器记录获取次数),每次获取只需对应释放,避免死锁。

二、怎么使用

以下是使用方法,对比参考

特性普通互斥量(Mutex)递归锁(Recursive Mutex)
重复获取同一任务重复获取 → 死锁(自己等自己)同一任务可重复获取(内部计数 + 1)
释放规则调用 xSemaphoreGive() 直接释放需调用 xSemaphoreGiveRecursive(),且获取次数需与释放次数配对
适用场景简单临界区(单层访问)嵌套临界区(多层函数调用需同一把锁)
创建 APIxSemaphoreCreateMutex()xSemaphoreCreateRecursiveMutex()
获取 APIxSemaphoreTake()xSemaphoreTakeRecursive()
释放 APIxSemaphoreGive()xSemaphoreGiveRecursive()

三、示例代码

/*
递归锁可以保证不同任务或者甚至是不同函数内创建的互斥量无法互相被获取或者释放(见Task5)。*//* Standard includes. */
#include <stdio.h>/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"/* Library includes. */
#include "stm32f10x_it.h"/* Demo app includes. */
#include "serial.h"/*-----------------------------------------------------------*//** Configure the clocks, GPIO and other peripherals as required by the demo.*/
static void prvSetupHardware( void );/** Retargets the C library printf function to the USART.*/
int fputc( int ch, FILE *f );/** Configures the timers and interrupts for the fast interrupt test as* described at the top of this file.*/
extern void vSetupTimerTest( void );/*-----------------------------------------------------------*/static int sum = 0;
static volatile int flagCalcEnd = 0;
static volatile int flagUARTused = 0;static SemaphoreHandle_t xSemCalc;
static SemaphoreHandle_t xSemUART;void Task1Function(void * param)
{volatile int i = 0;while (1){for (i = 0; i < 10000000; i++)sum++;//printf("1");xSemaphoreGive(xSemCalc);vTaskDelete(NULL);}
}void Task2Function(void * param)
{while (1){//if (flagCalcEnd)flagCalcEnd = 0;xSemaphoreTake(xSemCalc, portMAX_DELAY);flagCalcEnd = 1;printf("sum = %d\r\n", sum);}
}void TaskGenericFunction(void * param)
{int i;while (1){xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);printf("%s\r\n", (char *)param);for (i = 0; i < 10; i++){xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);printf("%s in loop %d\r\n", (char *)param, i);xSemaphoreGiveRecursive(xSemUART);}xSemaphoreGiveRecursive(xSemUART);vTaskDelay(1);}
}void Task5Function(void * param)
{vTaskDelay(10);while (1){while (1){if (xSemaphoreTakeRecursive(xSemUART, 0) != pdTRUE){xSemaphoreGiveRecursive(xSemUART);			}else{break;}}printf("%s\r\n", (char *)param);xSemaphoreGiveRecursive(xSemUART);vTaskDelay(1);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc = xSemaphoreCreateCounting(10, 0);//xSemUART = xSemaphoreCreateBinary();//xSemaphoreGive(xSemUART);//xSemUART = xSemaphoreCreateMutex();xSemUART = xSemaphoreCreateRecursiveMutex();xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);xTaskCreate(Task5Function, "Task5", 100, "Task 5 is running", 1, NULL);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}
/*-----------------------------------------------------------*//*-----------------------------------------------------------*//*-----------------------------------------------------------*/static void prvSetupHardware( void )
{/* Start with the clocks in their expected state. */RCC_DeInit();/* Enable HSE (high speed external clock). */RCC_HSEConfig( RCC_HSE_ON );/* Wait till HSE is ready. */while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET ){}/* 2 wait states required on the flash. */*( ( unsigned long * ) 0x40022000 ) = 0x02;/* HCLK = SYSCLK */RCC_HCLKConfig( RCC_SYSCLK_Div1 );/* PCLK2 = HCLK */RCC_PCLK2Config( RCC_HCLK_Div1 );/* PCLK1 = HCLK/2 */RCC_PCLK1Config( RCC_HCLK_Div2 );/* PLLCLK = 8MHz * 9 = 72 MHz. */RCC_PLLConfig( RCC_PLLSource_HSE_Div1, RCC_PLLMul_9 );/* Enable PLL. */RCC_PLLCmd( ENABLE );/* Wait till PLL is ready. */while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}/* Select PLL as system clock source. */RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );/* Wait till PLL is used as system clock source. */while( RCC_GetSYSCLKSource() != 0x08 ){}/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );/* SPI2 Periph clock enable */RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );/* Set the Vector Table base address at 0x08000000 */NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );/* Configure HCLK clock as SysTick clock source. */SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );SerialPortInit();
}
/*-----------------------------------------------------------*//*-----------------------------------------------------------*//*-----------------------------------------------------------*/#ifdef  DEBUG
/* Keep the linker happy. */
void assert_failed( unsigned char* pcFile, unsigned long ulLine )
{for( ;; ){}
}
#endif

http://www.xdnf.cn/news/14326.html

相关文章:

  • 1.18 进程管理PM2
  • 山东大学项目实训-创新实训-法律文书专家系统-项目报告(六)
  • 【数据结构中的堆】
  • ASR-PRO语音识别可能出现的问题
  • langchain从入门到精通(九)——ChatGPT/Playground手动模拟记忆功能
  • MFE微前端:如何捕捉远程应用的remote.js加载失败的错误?
  • 【人工智能数学基础】测度论
  • 11.OpenCV—联合QT环境配置
  • RTDETRv2 pytorch 官方版自己数据集训练遇到的问题解决
  • 正整数的正向分解
  • 股指期货的多空策略是什么?
  • 编译链接实战(30)strip移除了哪些内容
  • java设计模式[3]之结构性型模式
  • Druid 连接池详解
  • 基于CSO算法的任务卸载在IoT移动边缘计算
  • 绝对收敛 趋于 0 的速度足够快 | 条件收敛 --> 项趋于 0 正负项相互抵消
  • 语言模型的泛化能力和训练数据依赖性
  • Docker -- 快速入门
  • JavaScript 数据结构详解
  • Java垃圾回收机制
  • [NLP]课程期末知识点总结
  • [windows工具]PDFOCR识别导出Excel工具1.1版本使用教程及注意事项
  • 【JVM】- 类加载与字节码结构3
  • 性能优化 - 高级进阶:JVM 常见优化参数
  • Linux内核网络协议的双重注册机制:inet_add_protocol与inet_register_protosw深度解析
  • Python小酷库系列:Python中的JSON工具库(3)
  • 行为设计模式之State(状态)设计模式
  • java中常见的排序算法设计介绍
  • IDEA21中文乱码解决办法
  • ubuntu 22.04设置时区和24小时制显示——筑梦之路