freeRtos互斥量的使用

所以二进制并不能保证是谁上锁谁解锁,引入互斥量本质并没有解决这个问题,还是要程序员去解决。引入互斥量可以去解决优先级翻转的问题。

一.优先级反转和优先级继承

二. 递归上锁

获得了锁之后,再次执行任务获得锁。

三.创建互斥量 

与前面的信号量差不多,只不过前面创建信号量之前需要give一下,这里创建互斥量不需要give

void TaskGenericFunction(void * param)
{while (1){xSemaphoreTake(xSemUART,portMAX_DELAY);//获得信号量printf("%s\r\n", (char *)param);xSemaphoreGive(xSemUART);//释放信号量vTaskDelay(1);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc=xSemaphoreCreateCounting(10,0);xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);xSemUART=xSemaphoreCreateMutex();xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 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 volatile uint8_t flagLPTaskRun = 0;
static volatile uint8_t flagMPTaskRun = 0;
static volatile uint8_t flagHPTaskRun = 0;static void vLPTask( void *pvParameters );
static void vMPTask( void *pvParameters );
static void vHPTask( void *pvParameters );/*-----------------------------------------------------------*//* 互斥量/二进制信号量句柄 */
SemaphoreHandle_t xLock;int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateBinary( );xSemaphoreGive(xLock);//给一个初值if( xLock != NULL ){/* 创建3个任务: LP,MP,HP(低/中/高优先级任务)*/xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建互斥量/二进制信号量 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}/*-----------------------------------------------------------*//*-----------------------------------------------------------*/
static void vLPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );	uint32_t i;char c = 'A';printf("LPTask start\r\n");/* 无限循环 */for( ;; ){	flagLPTaskRun = 1;flagMPTaskRun = 0;flagHPTaskRun = 0;/* 获得互斥量/二进制信号量 */xSemaphoreTake(xLock, portMAX_DELAY);/* 耗时很久 */printf("LPTask take the Lock for long time");for (i = 0; i < 500; i++) {flagLPTaskRun = 1;flagMPTaskRun = 0;flagHPTaskRun = 0;printf("%c", c + i);}printf("\r\n");/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);vTaskDelay(xTicksToWait);}
}static void vMPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 30UL );	flagLPTaskRun = 0;flagMPTaskRun = 1;flagHPTaskRun = 0;printf("MPTask start\r\n");/* 让LPTask、HPTask先运行 */	vTaskDelay(xTicksToWait);/* 无限循环 */for( ;; ){	flagLPTaskRun = 0;flagMPTaskRun = 1;flagHPTaskRun = 0;}
}static void vHPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );	flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;printf("HPTask start\r\n");/* 让LPTask先运行 */	vTaskDelay(xTicksToWait);/* 无限循环 */for( ;; ){	flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;printf("HPTask wait for Lock\r\n");/* 获得互斥量/二进制信号量 */xSemaphoreTake(xLock, portMAX_DELAY);flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);}
}

 高优先级先执行执行Delay(10ms),接着中等优先级执行Delay(30ms),低优先级执行运行获得了LOCK,打印500个字符,高优先级任务想获得锁,没有成功进入阻塞状态,低优先级任务执行30ms到了,中优先级任务就一直执行,没有放弃执行。

修改原来的代码1为下面的代码2

    /* 创建互斥量/二进制信号量 */    xLock = xSemaphoreCreateBinary( );xSemaphoreGive(xLock);//给一个初值
    /* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateMutex();
int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateMutex();if( xLock != NULL ){/* 创建3个任务: LP,MP,HP(低/中/高优先级任务)*/xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建互斥量/二进制信号量 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}

前面一部分跟上面是一样的高优先级先执行,中接着执行,低优先任务最后执行,低优先级任务里面获得了LOCK,10ms执行时间到了高优先级任务想要LOCK,进入阻塞状态同时会优先级继承,最低优先级继承最高优先级,即使到了中优先级该执行的时间了,但是还是低优先级执行,最后UNLOCK,轮到最高优先级执行。

五.互斥量的缺陷和递归锁

递归锁可以实现由谁持有就由谁释放。

void TaskGenericFunction(void * param)
{while (1){xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);printf("%s\r\n", (char *)param);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);		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 = 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;
}

递归上锁解锁 

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);		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 = 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/276557.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Axure的动态图使用以及说明

认识Axure动态图 Axure动态图是Axure中的一种功能&#xff0c;它允许用户在原型中添加动画效果和交互动作&#xff0c;使原型更加生动和具有真实的用户体验。用户可以通过添加动态图来展示页面过渡、按钮点击、下拉菜单等交互操作的效果。 这是&#xff1a;就是我们今天要叫的…

mysql原理--B+树索引

1.没有索引的查找 1.1.在一个页中的查找 (1). 以主键为搜索条件 可以在 页目录 中使用二分法快速定位到对应的槽&#xff0c;然后再遍历该槽对应分组中的记录即可快速找到指定的记录。 (2). 以其他列作为搜索条件 这种情况下只能从 最小记录 开始依次遍历单链表中的每条记录&am…

使用qt实现四则运算计算机项目

这是我们要包含的头文件 #include <QWidget> #include<QStack> #include<string.h> #include<string> 这是我在ui界面创建的计算机基础框架。 接下来要实现按住每个按钮在白框内显示&#xff1b; 因此我们要定义一个QString 类型的变量 QString e…

GaussDB如何创建和管理视图

GaussDB如何创建和管理视图 一、什么是视图 当用户对数据库中的一张或者多张表的某些字段的组合感兴趣&#xff0c;而又不想每次键入这些查询时&#xff0c;用户就可以定义一个视图&#xff0c;以便解决这个问题。 视图与基本表不同&#xff0c;不是物理上实际存在的&#x…

Vue学习计划-Vue2--VueCLi(六)插槽、过渡

写在最前&#xff1a;父组件引用子组件&#xff0c;如何能在应用子组件内容的同时&#xff0c;还能在自定义内容呢&#xff1f; 1. 插槽 作用&#xff1a; 让父组件可以向子组件指定位置插入html结构&#xff0c;也是一种组件通信的方式&#xff0c;适用于父组件>子组件分…

基础算法(3):排序(3)插入排序

1.插入排序实现 插入排序的工作原理是&#xff1a;通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已经排序的序列从后向前扫描&#xff0c;找到位置并插入&#xff0c;类似于平时打扑克牌时&#xff0c;将牌从大到小排列&#xff0c;每次摸到一张牌就插入到正确的位…

弹性搜索引擎Elasticsearch:本地部署与远程访问指南

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言系统环境1. Windows 安装Elasticsearch2. 本地访问Elasticsearch3. Windows 安装…

柯桥西班牙语里最“好用”的脏话:一些关于cojones的表达

Creo que una de las palabras con ms contextos donde se puede utilizar y que adems pronto es conocida por los estudiantes de espaol es esta que est en el ttulo. 相信标题中的这个单词“cojones”&#xff0c;使用时总是包含很多含义&#xff0c;同时也是西语学习者最…

VBA快速填充缺失数据

实例需求&#xff1a;数据表中F列中存在数据缺失&#xff0c;如下图所示。现需要根据A列中的内容&#xff08;类别&#xff0c;图中C1、C2、B1为不同类别&#xff09;&#xff0c;补充F列数据&#xff0c;已知每个类别中F列存在不少于一个非空单元格&#xff0c;并且其内容相同…

MPC814 DIP4封装交流输入光电晶体管耦合器

晶体管光电耦合器是一种将光信号转换为电信号的器件&#xff0c;其工作原理是通过光电二极管将光信号转换为电流信号&#xff0c;然后经过晶体管放大&#xff0c;输出相应的电压信号&#xff1b;具有高转换效率较高的灵敏度和快速响应等特点。 由工采网代理的MPC814系列结合了两…

Linux 非阻塞网络IO模式

非阻塞网络IO模式介绍 当用户线程发起一个 read 操作后&#xff0c;并不需要等待&#xff0c;而是马上就得到了一个结果。如果结果是一个 error 时&#xff0c;它就知道数据还没有准备好&#xff0c;于是它可以再次发送 read 操作。一旦内核中的数据准备好了&#xff0c;并且又…

Android笔记(十八):面向Compose组件结合Retrofit2和Rxjava3实现网络访问

一、Retrofit2 Square公司推出的Retrofit2库&#xff08;https://square.github.io/retrofit/&#xff09;&#xff0c;改变了网络访问的方式。它实现了网络请求的封装。Retrofit库采用回调处理方式&#xff0c;使得通过接口提交请求和相应的参数的配置&#xff0c;就可以获得…