C语言Freertos的递归锁详解

Zandra ·
更新时间:2024-09-20
· 1331 次阅读

目录

1.死锁的概念

2.自我死锁

3.递归锁

4.代码

5.运行流程分析

6.运行结果

总结

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

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

3.递归锁

1.任务 A 获得递归锁 M 后,它还可以多次去获得这个锁

2."take"了 N 次,要"give"N 次,这个锁才会被释放

3.谁上锁就由谁解锁。

递归锁的函数根一般互斥量的函数名不一样

 递归锁一般互斥量
创建xSemaphoreCreateRecursiveMutexxSemaphoreCreateMutex
获得xSemaphoreTakeRecursivexSemaphoreTake
释放xSemaphoreGiveRecursivexSemaphoreGive
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.运行结果

总结

谁持有递归锁,必须由谁释放。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注软件开发网的更多内容!    



freertos 递归

需要 登录 后方可回复, 如果你还没有账号请 注册新账号