FreeRTOS基础入门——FreeRTOS优先级翻转(十五)

news2024/9/21 14:41:21

 个人名片:

🎓作者简介:嵌入式领域优质创作者
🌐个人主页:妄北y

📞个人QQ:2061314755

💌个人邮箱:[mailto:2061314755@qq.com]
📱个人微信:Vir2025WBY

🖥️个人公众号:科技妄北
🖋️本文为妄北y原创佳作,独家首发于CSDN🎊🎊🎊
💡座右铭:改造世界固然伟大,但改造自我更为可贵。

专栏导航:

妄北y系列专栏导航:

物联网嵌入式开发项目:大学期间的毕业设计,课程设计,大创项目,各种竞赛项目,全面覆盖了需求分析、方案设计、实施与调试、成果展示以及总结反思等关键环节。📚💼💡

QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作。🛠️🔧💭

Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。🍻🎉🖥️

深耕Linux应用开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。常见开源库的二次开发,如libcurl、OpenSSL、json-c、freetype等💐📝💡

Linux驱动开发:Linux驱动开发是Linux系统不可或缺的组成部分,它专注于编写特殊的程序——驱动程序。这些程序承载着硬件设备的详细信息,并扮演着操作系统与硬件间沟通的桥梁角色。驱动开发的核心使命在于确保硬件设备在Linux系统上顺畅运作,同时实现与操作系统的无缝集成,为用户带来流畅稳定的体验。🚀🔧💻

Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。🤸🌱🚀

非常期待与您一同在这个广阔的互联网天地里,携手探索知识的海洋,互相学习,共同进步。🌐💫🌱 熠熠星光,照亮我们的成长之路

✨✨ 欢迎订阅本专栏,对专栏内容任何问题都可以随时联系博主,共同书写属于我们的精彩篇章!✨✨

文章介绍:

📚本篇文章将深入剖析RTOS学习的精髓与奥秘,与您一同分享相关知识!🎉🎉🎉

若您觉得文章尚可入目,期待您能慷慨地送上点赞、收藏与分享的三连支持!您的每一份鼓励,都是我创作路上源源不断的动力。让我们携手并进,共同奔跑,期待在顶峰相见的那一天,共庆辉煌!🚀🚀🚀

🙏衷心感谢大家的点赞👍、收藏⭐和评论✍️,您的支持是我前进的动力!

目录:

目录:

一、 什么是优先级翻转?

二、程序设计:

2.1 设计目的

2.2 任务设置:

2.3 main()函数:

2.4 任务函数:

三、程序运行结果分析:

3.1 任务和信号量的状态:

3.2 优先级反转的现象:

3.3 优先级反转的问题:

3.4 解决优先级反转的方法:


一、 什么是优先级翻转?

使用二值信号量的过程中,优先级翻转是一个常见且重要的问题。在可剥夺的内核环境中,优先级翻转现象尤其普遍,这在实时系统中是不可接受的,因为它会扰乱任务的预定执行顺序,并可能导致严重的后果。图1-1 展示了优先级翻转的一个示例。

 

在这个场景中,我们可以把任务H、任务M和任务L的执行过程描述为一个优先级翻转的示例。具体情况如下:

        1. 任务H和任务M处于挂起状态,等待某个事件发生,而任务L正在正常运行。

        2. 当任务L需要访问一个共享资源时,它必须首先获取该资源的信号量。

        3. 任务L成功地获得了信号量并开始使用共享资源。

        4. 随着时间的推移,任务H由于其优先级高,事件发生后抢占了任务L的CPU使用权。

        5. 任务H开始执行。

        6. 在任务H运行时,它也需要访问任务L正在使用的共享资源。然而,由于该资源的信号量仍被任务L占用,任务H只能处于挂起状态,等待任务L释放信号量。

        7. 任务L继续运行其余的工作。

        8. 不久后,任务M由于优先级高于任务L,当它等待的事件发生后,它也剥夺了任务L的CPU使用权。

        9. 任务M开始处理其相关事务。

        10. 任务M完成任务后,将CPU使用权归还给任务L。

        11. 任务L在得到CPU之后继续运行。

        12. 最终,任务L完成了所有工作并释放了信号量。由于实时内核意识到有一个高优先级任务(任务H)在等待此信号量,内核进行任务切换。

        13. 任务H获得信号量后继续执行。

在此过程中,任务H的优先级实际上被降低至任务L的优先级水平。这是因为任务H必须等待任务L释放其占用的共享资源。由于任务M抢占了任务L的CPU使用权,任务H的状况变得更加不利,导致优先级翻转现象的发生。这种情况表明,虽然任务H的优先级高于任务L,但由于资源竞争的关系,任务M的优先级实际上高于任务H,从而引发了优先级翻转。

二、程序设计:

2.1 设计目的

本实验设计了四个任务:start taskhigh taskmiddle tasklow task,各任务的功能如下:

  • start task:负责创建其他三个任务。
  • high task:高优先级任务,将获取二值信号量。在成功获取后,执行相关处理,并在完成后释放该信号量。
  • middle task:中等优先级任务,作为一个简单的应用任务,功能较为基础。
  • low task:低优先级任务,与高优先级任务相似,同样获取二值信号量。在成功获取后,会执行相关处理,但低优先级任务占用信号量的时间较长(通过软件模拟实现)。

在实验过程中,我们创建了一个二值信号量BinarySemaphore,高优先级任务和低优先级任务都将使用该信号量。

2.2 任务设置:

//任务优先级
#define START_TASK_PRIO			1
//任务堆栈大小	
#define START_STK_SIZE 			256  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define LOW_TASK_PRIO			2
//任务堆栈大小	
#define LOW_STK_SIZE 			256  
//任务句柄
TaskHandle_t LowTask_Handler;
//任务函数
void low_task(void *pvParameters);

//任务优先级
#define MIDDLE_TASK_PRIO 		3
//任务堆栈大小	
#define MIDDLE_STK_SIZE  		256 
//任务句柄
TaskHandle_t MiddleTask_Handler;
//任务函数
void middle_task(void *pvParameters);

//任务优先级
#define HIGH_TASK_PRIO 			4
//任务堆栈大小	
#define HIGH_STK_SIZE  			256 
//任务句柄
TaskHandle_t HighTask_Handler;
//任务函数
void high_task(void *pvParameters);

//二值信号量句柄
SemaphoreHandle_t BinarySemaphore;	//二值信号量

//LCD刷屏时使用的颜色
int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
						GRED,  GBLUE, RED,   MAGENTA,       	 
						GREEN, CYAN,  YELLOW,BROWN, 			
						BRRED, GRAY };

2.3 main()函数:

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	 
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_Init();							//初始化按键
	BEEP_Init();						//初始化蜂鸣器
	LCD_Init();							//初始化LCD
	my_mem_init(SRAMIN);            	//初始化内部内存池

    POINT_COLOR = RED;
	LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");	
	LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 14-3");
	LCD_ShowString(30,50,200,16,16,"Priority Overturn");
	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,90,200,16,16,"2016/11/25");
	
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

2.4 任务函数:

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	
	//创建二值信号量
	BinarySemaphore=xSemaphoreCreateBinary();
	//二值信号量创建成功以后要先释放一下
	if(BinarySemaphore!=NULL)xSemaphoreGive(BinarySemaphore);	
	
    //创建高优先级任务
    xTaskCreate((TaskFunction_t )high_task,             
                (const char*    )"high_task",           
                (uint16_t       )HIGH_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )HIGH_TASK_PRIO,        
                (TaskHandle_t*  )&HighTask_Handler);   
    //创建中等优先级任务
    xTaskCreate((TaskFunction_t )middle_task,     
                (const char*    )"middle_task",   
                (uint16_t       )MIDDLE_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )MIDDLE_TASK_PRIO,
                (TaskHandle_t*  )&MiddleTask_Handler); 
	//创建低优先级任务
    xTaskCreate((TaskFunction_t )low_task,     
                (const char*    )"low_task",   
                (uint16_t       )LOW_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )LOW_TASK_PRIO,
                (TaskHandle_t*  )&LowTask_Handler);
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//高优先级任务的任务函数
void high_task(void *pvParameters)
{
	u8 num;
	
	POINT_COLOR = BLACK;
	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
	LCD_DrawLine(5,130,115,130);		//画线
	POINT_COLOR = BLUE;
	LCD_ShowString(6,111,110,16,16,"High Task");
	
	while(1)
	{
		vTaskDelay(500);	//延时500ms,也就是500个时钟节拍	
		num++;
		printf("high task Pend Sem\r\n");
		xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取二值信号量
		printf("high task Running!\r\n");
		LCD_Fill(6,131,114,313,lcd_discolor[num%14]); 	//填充区域
		LED1=!LED1;
		xSemaphoreGive(BinarySemaphore);				//释放信号量
		vTaskDelay(500);	//延时500ms,也就是500个时钟节拍  
	}
}

//中等优先级任务的任务函数
void middle_task(void *pvParameters)
{
	u8 num;
	
	POINT_COLOR = BLACK;
	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
	LCD_DrawLine(125,130,234,130);		//画线
	POINT_COLOR = BLUE;
	LCD_ShowString(126,111,110,16,16,"Middle Task");
	while(1)
	{
		num++;
		printf("middle task Running!\r\n");
		LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //填充区域
		LED0=!LED0;
        vTaskDelay(1000);	//延时1s,也就是1000个时钟节拍	
	}
}

//低优先级任务的任务函数
void low_task(void *pvParameters)
{
	static u32 times;

	while(1)
	{
		xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取二值信号量
		printf("low task Running!\r\n");
		for(times=0;times<5000000;times++)				//模拟低优先级任务占用二值信号量
		{
			taskYIELD();								//发起任务调度
		}
		xSemaphoreGive(BinarySemaphore);				//释放二值信号量
		vTaskDelay(1000);	//延时1s,也就是1000个时钟节拍	
	}
}

三、程序运行结果分析:

编译并下载实验代码到开发板中,打开串口调试助手,默认情况下LCD显示如图 3-1 所示。

图 3-1 LCD默认画面 

从LCD上不容易看出优先级翻转的现象,我们可以通过串口很方便的观察优先级翻转,串口输出如图 3-2 所示。

图 3-2 串口输出

为了方便分析,我们将串口输出复制出来,如下:

·LCD ID:5510
middle task Running!
low task Running!               
high task Pend Sem              
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!
middle task Running!

high task Running!
middle task Running!
high task Pend Sem

3.1 任务和信号量的状态

  • 低优先级任务(low_task)获取到二值信号量(BinarySemaphore),并开始运行。
  • 高优先级任务(high_task)尝试获取同一个信号量,但由于该信号量被低优先级任务占用,因此高优先级任务必须等待,直到低优先级任务释放信号量。

3.2 优先级反转的现象

  • 在此情况下,尽管高优先级任务(high_task)具有更高的优先级,但由于低优先级任务(low_task)持有信号量,它无法运行。
  • 中等优先级任务(middle_task)能够在低优先级任务运行时抢占CPU资源,因此中等优先级任务的执行会导致高优先级任务的延迟,造成高优先级任务在等待信号量的同时被中等优先级任务打断,这就是优先级反转的现象。

3.3 优先级反转的问题

  • 此现象会导致高优先级任务的响应时间显著增加,从而影响系统的实时性能。

3.4 解决优先级反转的方法

  • 一种有效的解决方案是使用互斥信号量(Mutex Semaphore)。互斥信号量可以确保在低优先级任务持有资源时,如果高优先级任务请求资源,系统会提升低优先级任务的优先级到高优先级任务的级别,直到它释放资源。这种方法可以防止中等优先级任务抢占低优先级任务,从而避免优先级反转的发生。

📝大佬觉得本文有所裨益,不妨轻点一下👍给予鼓励吧!

❤️❤️❤️本人虽努力,但能力尚浅,若有不足之处,恳请各位大佬不吝赐教,您的批评指正将是我进步的动力!😊😊😊

💖💖💖若您认为此篇文章对您有所帮助,烦请点赞👍并收藏🌟,您的支持是我前行的最大动力!

🚀🚀🚀任务在默默中完成,价值在悄然间提升。让我们携手共进,一起加油,迎接更美好的未来!🌈🌈🌈

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【重磅升级】积木报表 v1.8.1 版本发布,支持填报功能

项目介绍 一款免费的数据可视化报表工具&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完…

[数据结构] 开散列法 闭散列法 模拟实现哈希结构

标题&#xff1a;[数据结构] 开散列法 && 闭散列法 模拟实现哈希结构 个人主页&#xff1a;水墨不写bug 目录 一、闭散列法 核心逻辑的解决 i、为什么要设置位置状态&#xff1f;&#xff08;伪删除法的使用&#xff09; ii、哈希函数的设计 接口的实现 1、插入&a…

SD三分钟入门!秋叶大佬24年8月最新的Stable Diffusion整合包V4.9.7来了~

1 什么是 Stable Diffusion&#xff1f; Stable Diffusion&#xff08;简称SD&#xff09;是一种生成式人工智能技术&#xff0c;于2022年推出。它主要用于根据文本描述生成精细图像&#xff0c;同时也可应用于其他任务&#xff0c;如图像修补、扩展&#xff0c;以及在文本提…

圣诞节:白酒与西式料理的异国风情

随着冬日的脚步渐近&#xff0c;圣诞的钟声即将敲响。在这个充满异国情调和温馨氛围的节日里&#xff0c;一场中西合璧的美食盛宴悄然上演。豪迈白酒&#xff08;HOMANLISM&#xff09;与西式料理的碰撞&#xff0c;不仅为圣诞餐桌增添了几分不同的韵味&#xff0c;更让人们在这…

标准库_string的代码实现

前言 string不属于stl&#xff0c;string比stl出现的早的多&#xff0c;所以string属于标准库&#xff0c;不属于stl 大家可以在cplusplus网站看string的内容 string的六个构造函数 构造函数 在写构造函数的时候不管传的字符串里面有没有字符&#xff0c;都必须至少要new c…

zerojs前端面试题系列--vue3篇(4)

1. Vue3中的可选链运算符&#xff08;?.&#xff09;和空值合并运算符&#xff08;??&#xff09;是什么&#xff1f;它们有什么作用&#xff1f; 可选链运算符&#xff08;?.&#xff09;和空值合并运算符&#xff08;??&#xff09;是Vue 3.x中新增的两种运算符。 可选…

点餐小程序实战教程04变量定义和初始化

目录 1 什么是变量2 如何创建变量3 具体该选择什么类型4 变量的初始化5 await/async6 调试我们的程序7 运行我们的代码总结 日常碰到的最多的一句话是&#xff0c;我看到代码就发憷&#xff0c;我一点基础也没有。那低代码开发需要掌握什么样的基础&#xff0c;怎么才算是掌握了…

图像分割像素三分类效果

pets_fg 数据集 训练集: avg_score: 0.8818 - dice: 0.9138 - iou: 0.8520 - loss: 0.1116 - mae: 0.6862 训练集掩码效果 avg_score: 0.8415 - dice: 0.8798 - iou: 0.8065 - loss: 0.1601 - mae: 0.6882 验证集效果展示

提前锁定!2024云栖大会大数据AI参会攻略来啦

2024年9月19日~9月21日&#xff0c;一年一度的云栖大会又要与大家见面了。一文尽览大数据AI精彩预告&#xff0c;赶紧收藏吧&#xff01; 9月20日上午 10:45~11:25 阿里云智能集团副总裁、计算平台事业部负责人汪军华带来大数据AI平台年度发布。揭晓全新的 OpenLake 方案如何为…

力扣题解2181

大家好&#xff0c;欢迎来到无限大的频道&#xff0c;有些日子没更新了&#xff08;其实是因为懒&#xff09; 言归正传&#xff0c;开始分享今日的题解。 题目描述&#xff1a; 合并零之间的节点 给一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。…

七种方法加密图纸!2024企业要如何对CAD图纸进行加密?

随着企业信息化的发展&#xff0c;CAD图纸作为企业的核心数据之一&#xff0c;其安全性变得尤为重要。如何有效加密CAD图纸&#xff0c;以防止数据泄露&#xff0c;是众多企业关注的重点问题。本文将介绍2024年企业加密CAD图纸的七种有效方法&#xff0c;帮助企业提升图纸安全性…

记一次高版本view-design的组件迁移到自身项目的低版本

背景 npm i -S view-design当前老项目使用view-design这个组件库&#xff0c;但是当我们去官网查看该组件库最新版本&#xff0c;竟然发现没有博主想用的image/ImagePreivew这两个基础组件 说实话&#xff0c;有点离谱了哈&#xff01;&#xff01; 自己造轮子&#xff1f; …

软考基础知识之网络工程

目录 前言 网络工程 网络规划 1、网络需求分析 2、可行性研究 3、对现有网络的分析与描述 网络设计 1、网络逻辑结构设计 2、网络物理结构设计 3、 分层设计 网络实施 1、工程实施计划 2、网络设备到货验收 3、设备安装 4、系统测试 5、系统试运行 6、用户培训…

利用熵权法进行数值评分计算——算法过程

1、概述 在软件系统中&#xff0c;研发人员常常遇上需要对系统内的某种行为/模型进行评分的情况。例如根据系统的各种漏洞情况对系统安全性进行评分、根据业务员最近操作系统的情况对业务员工作状态进行打分等等。显然研发人员了解一种或者几种标准评分算法是非常有利于开展研…

mp4转文字怎么快速转换?5个软件教你快速进行视频提取文字

mp4转文字怎么快速转换&#xff1f;5个软件教你快速进行视频提取文字 将MP4视频转换为文字是一项常见的需求&#xff0c;尤其是在需要将视频中的对话、演讲或字幕转为文本时。通过使用AI转录软件&#xff0c;你可以快速将视频中的音频内容提取并转换为文字。以下介绍5款可以帮…

一个数组向左移动i位(学会分析问题,找出规律,不要小看任何一个小程序;小程序都是实现大的功能的基础--体现问题分解的思想)

学会分析问题&#xff0c;找出规律&#xff1b; 不要小看任何一个小程序&#xff0c;小程序都是实现大的功能的基础--体现问题分解的思想&#xff09; 思想火花--好算法是反复努力和重新修正的结果 解法1:先将数组中的前i个元素存放在一个临时数组中,再将余下的n一i个元素左…

黑马点评15——分布式缓存-Redis分片集群

文章目录 搭建分片集群散列插槽集群伸缩故障转移RedisTemplate访问分片集群 搭建分片集群 参考我前面的文章&#xff1a;单机部署Redis集群 散列插槽 集群伸缩 添加新的节点后要重新分配插槽, 故障转移 这是自动的故障转移&#xff0c;但有时候需要手动的故障转移——比如更…

Hfinger:一款针对恶意软件HTTP请求的指纹识别工具

关于Hfinger Hfinger是一款功能强大的HTTP请求指纹识别工具&#xff0c;该工具使用纯Python开发&#xff0c;基于Tshark实现其功能&#xff0c;可以帮助广大研究人员对恶意软件的 HTTP 请求进行指纹识别。 该工具的主要目标是提供恶意软件请求的唯一表示&#xff08;指纹&…

“CSS 定位”如何工作?(补充)——WEB开发系列34

CSS定位是一个非常重要的布局工具&#xff0c;它允许我们精确地控制元素的位置&#xff0c;从而创建复杂的布局效果。定位允许你从正常的文档流布局中取出元素&#xff0c;并使它们具有不同的行为&#xff0c;例如放在另一个元素的上面&#xff0c;或者始终保持在浏览器视窗内的…

Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计

文章目录 Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计1. 前言2. SQL注入代码审计【有1处】1&#xff09;全局搜索Statement关键字&#xff0c;发现有几处&#xff0c;不过大多都是preparStatement预编译方式执行sql语句。2&#xff09;点进第一个看看3&am…