C语言|C语言 Freertos的递归锁详解

目录

  • 1.死锁的概念
  • 2.自我死锁
  • 3.递归锁
  • 4.代码
  • 5.运行流程分析
  • 6.运行结果
  • 总结

1.死锁的概念
假设有 2 个互斥量 M1、 M2, 2 个任务 A、 B:A 获得了互斥量 M1B 获得了互斥量 M2A 还要获得互斥量 M2 才能运行,结果 A 阻塞B 还要获得互斥量 M1 才能运行,结果 B 阻塞A、 B 都阻塞,再无法释放它们持有的互斥量死锁发生!

C语言|C语言 Freertos的递归锁详解
文章图片


2.自我死锁
任务 A 获得了互斥锁 M它调用一个函数函数要去获取同一个互斥锁 M,于是它阻塞:任务 A 休眠,等待任务 A来释放互斥锁!死锁发生!

C语言|C语言 Freertos的递归锁详解
文章图片


3.递归锁 1.任务 A 获得递归锁 M 后,它还可以多次去获得这个锁
2."take"了 N 次,要"give"N 次,这个锁才会被释放
3.谁上锁就由谁解锁。
递归锁的函数根一般互斥量的函数名不一样
递归锁 一般互斥量
创建 xSemaphoreCreateRecursiveMutex xSemaphoreCreateMutex
获得 xSemaphoreTakeRecursive xSemaphoreTake
释放 xSemaphoreGiveRecursive xSemaphoreGive

4.代码 main
/* 递归锁句柄 */SemaphoreHandle_t xMutex; int main( void ){ prvSetupHardware(); /* 创建递归锁 */xMutex = xSemaphoreCreateRecursiveMutex( ); if( xMutex != NULL ) {/* 创建2个任务: 一个上锁, 另一个自己监守自盗(开别人的锁自己用)xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL ); xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL ); /* 启动调度器 */vTaskStartScheduler(); } else {/* 无法创建递归锁 */ } return 0; }

任务1
static void vTakeTask( void *pvParameters ){ const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL ); BaseType_t xStatus; int i; /* 无限循环 */ for( ; ; ) { /* 获得递归锁: 上锁 */xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY); printf("Task1 take the Mutex in main loop %s\r\n", \(xStatus == pdTRUE)? "Success" : "Failed"); /* 阻塞很长时间, 让另一个任务执行, * 看看它有无办法再次获得递归锁 */vTaskDelay(xTicksToWait); for (i = 0; i < 10; i++){/* 获得递归锁: 上锁 */xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY); printf("Task1 take the Mutex in sub loop %s, for time %d\r\n", \(xStatus == pdTRUE)? "Success" : "Failed", i); /* 释放递归锁 */xSemaphoreGiveRecursive(xMutex); }/* 释放递归锁 */xSemaphoreGiveRecursive(xMutex); }}

任务2
static void vGiveAndTakeTask( void *pvParameters ){ const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL ); BaseType_t xStatus; /* 尝试获得递归锁: 上锁 */ xStatus = xSemaphoreTakeRecursive(xMutex, 0); printf("Task2: at first, take the Mutex %s\r\n", \(xStatus == pdTRUE)? "Success" : "Failed"); /* 如果失败则监守自盗: 开锁 */ if (xStatus != pdTRUE) {/* 无法释放别人持有的锁 */xStatus = xSemaphoreGiveRecursive(xMutex); printf("Task2: give Mutex %s\r\n", \(xStatus == pdTRUE)? "Success" : "Failed"); } /* 如果无法获得, 一直等待 */ xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY); printf("Task2: and then, take the Mutex %s\r\n", \(xStatus == pdTRUE)? "Success" : "Failed"); /* 无限循环 */ for( ; ; ) { /* 什么都不做 */vTaskDelay(xTicksToWait); }}


5.运行流程分析 1.任务 1 优先级最高,先运行,获得递归锁
2.任务 1 阻塞,让任务 2 得以运行
3.任务 2 运行,看看能否获得别人持有的递归锁: 不能
4.任务 2 故意执行"give"操作,看看能否释放别人持有的递归锁:不能
5.任务 2 等待递归锁
6.任务 1 阻塞时间到后继续运行,使用循环多次获得、释放递归锁

6.运行结果 【C语言|C语言 Freertos的递归锁详解】C语言|C语言 Freertos的递归锁详解
文章图片


总结 谁持有递归锁,必须由谁释放。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

    推荐阅读