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 都阻塞,再无法释放它们持有的互斥量死锁发生!
文章图片
2.自我死锁
任务 A 获得了互斥锁 M它调用一个函数函数要去获取同一个互斥锁 M,于是它阻塞:任务 A 休眠,等待任务 A来释放互斥锁!死锁发生!
文章图片
3.递归锁 1.任务 A 获得递归锁 M 后,它还可以多次去获得这个锁
2."take"了 N 次,要"give"N 次,这个锁才会被释放
3.谁上锁就由谁解锁。
递归锁的函数根一般互斥量的函数名不一样
递归锁 | 一般互斥量 | |
---|---|---|
创建 | xSemaphoreCreateRecursive Mutex |
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的递归锁详解】
文章图片
总结 谁持有递归锁,必须由谁释放。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- idea启动spring项目中文乱码的解决方法
- mybatis源码解读-Java中executor包的语句处理功能
- Nebula Graph 在企查查的应用
- 使用基于|使用基于 WebRTC 的 JavaScript API 在浏览器环境里调用本机摄像头
- Clickhouse中的预聚合引擎
- 如何使用|如何使用 Chrome 调试运行在手机上的 SAP UI5 Cordova 混合应用试读版
- 历史上的今天|【历史上的今天】3 月 16 日(开源精神奠基人诞生;技术先驱为女儿发明拍照手机;Minix 开发者出生)
- spring boot 保存到mysql时间不对的问题
- 不借助|不借助 Fiori client,直接在手机浏览器里调用 SAP UI5 BarcodeScanner 实现条形码扫描的可能性()
- 如何使用|如何使用 Cordova 将 SAP UI5 应用生成一个能在 Android 手机上安装的混合应用试读版