FreeRTOS 优先级翻转以及互斥信号量

news2024/9/20 16:25:24

优先级翻转:

高优先级的任务反而慢执行,低优先级的任务反而优先执行

        优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。

        在使用二值信号量的时候,经常会遇到优先级翻转的问题。

        高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)

 H(高优先级)                                        M(中优先级)                                         L(低优先级)

优先级翻转实验

实验目的:在使用二值信号量的时候会存在优先级翻转的问题,本实验通过模拟的方式实现优先级翻转,观察优先级翻转对抢占式内核的影响

实验设计:将设计四个任务:start_task、high_task、 middle_task , low_task

四个任务的功能如下:

  • start_task:用来创建其他的3个任务
  • high_task:高优先级任务,会获取二值信号量,获取成功以后打印提示信息,处理完后释放信号量
  • middle_task:中等优先级任务,简单的应用任务
  • low_task:低优先级任务,同高优先级一样的操作,不同的是低优先级任务占用信号量的时间久一点

代码 :

SemaphoreHandle_t Semaphore;                /* 计数型信号量 */
void start_task(void *pvParameters)
{
	
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建计数型信号量 */
    Semaphore = xSemaphoreCreateCounting(1, 1);
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )high_task,
                (const char*    )"high_task",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )middle_task,
                (const char*    )"middle_task",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    /* 创建任务3 */
    xTaskCreate((TaskFunction_t )low_task,
                (const char*    )"low_task",
                (uint16_t       )TASK3_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK3_PRIO,
                (TaskHandle_t*  )&Task3Task_Handler);
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

void high_task(void *pvParameters)
{
    vTaskDelay(1000);
    while (1)
    {
        printf("high_task 获取信号量\r\n");
        xSemaphoreTake(Semaphore, portMAX_DELAY);       /* 获取计数型信号量 */
        printf("high_task 获取成功\r\n");
        printf("high_task 正在运行\r\n");
        printf("high_task 释放信号量\r\n");
        xSemaphoreGive(Semaphore);                      /* 释放计数型信号量 */
        vTaskDelay(10000);
    }
}


void middle_task(void *pvParameters)
{
    uint32_t middle_task_num = 0;   
	vTaskDelay(1000);
    while (1)
    {
        for (middle_task_num=0; middle_task_num<5; middle_task_num++)
        {
            printf("middle_task 正在运行\r\n");
            delay_ms(1000);                              /* 模拟运行,不触发任务调度 */
        }
        vTaskDelay(10000);
    }
}


void low_task(void *pvParameters)
{
    uint32_t low_task_num = 0;
    
    while (1)
    {
        printf("low_task 获取信号量\r\n");
        xSemaphoreTake(Semaphore, portMAX_DELAY);       /* 获取计数型信号量 */
        printf("low_task 获取成功\r\n");
        for (low_task_num=0; low_task_num<5; low_task_num++)
        {
            printf("low_task 正在运行\r\n");
            delay_ms(1000);                              /* 模拟运行,不触发任务调度 */
        }
        printf("low_task 释放信号量\r\n");
        xSemaphoreGive(Semaphore);                      /* 释放计数型信号量 */
        vTaskDelay(1000);
	}
}

实验结果:

实验注意:延迟时间,确保有足够的延迟时间使中优先级任务和低优先级任务运行 

 

 互斥信号量

        互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!

优先级继承:

        当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。

         此时任务H的阻塞时间仅仅是任务L 的执行时间,将优先级翻转的危害降到了最低。

 

 优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响

注意:互斥信号量不能用于中断服务函数中,原因如下:

  1. 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
  2. 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

互斥信号量相关API函数

使用互斥信号量:首先将 宏 configUSE_MUTEXES 置一

使用流程:创建互斥信号量\rightarrow(task)获取信号量 \rightarrow(give)释放信号量

创建互斥信号量函数:

函数

描述

xSemaphoreCreateMutex()

使用动态方法创建互斥信号量。

xSemaphoreCreateMutexStatic()

使用静态方法创建互斥信号量。

返回值

描述

NULL

创建失败

其他值

创建成功返回互斥信号量的句柄

 此函数用于创建互斥信号量 

#define   xSemaphoreCreateMutex (   )                     \
          xQueueCreateMutex     (queueQUEUE_TYPE_MUTEX )

互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不支持中断中调用 

注意:创建互斥信号量时,会主动释放一次信号量 

互斥信号量实验 

实验目的:在优先级翻转实验的基础,加入互斥信号量,解决优先级翻转问题

实验设计:将优先级翻转所用到的信号量函数,修改成互斥信号量即可,通过串口打印提示信息

代码:

整体和上份没有太大区别,仅是使用了 互斥信号量

SemaphoreHandle_t MutexSemaphore;                /* 互斥信号量 */
void start_task(void *pvParameters)
{
	
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建互斥信号量 */
    MutexSemaphore = xSemaphoreCreateMutex();
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )high_task,
                (const char*    )"high_task",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )middle_task,
                (const char*    )"middle_task",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    /* 创建任务3 */
    xTaskCreate((TaskFunction_t )low_task,
                (const char*    )"low_task",
                (uint16_t       )TASK3_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK3_PRIO,
                (TaskHandle_t*  )&Task3Task_Handler);
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

void high_task(void *pvParameters)
{
    vTaskDelay(1000);
    while (1)
    {
        printf("high_task 获取信号量\r\n");
        xSemaphoreTake(MutexSemaphore, portMAX_DELAY);       /* 获取计数型信号量 */
        printf("high_task 获取成功\r\n");
        printf("high_task 正在运行\r\n");
        printf("high_task 释放信号量\r\n");
        xSemaphoreGive(MutexSemaphore);                      /* 释放计数型信号量 */
        vTaskDelay(10000);
    }
}


void middle_task(void *pvParameters)
{
    uint32_t middle_task_num = 0;   
	vTaskDelay(1000);
    while (1)
    {
        for (middle_task_num=0; middle_task_num<5; middle_task_num++)
        {
            printf("middle_task 正在运行\r\n");
            delay_ms(1000);                              /* 模拟运行,不触发任务调度 */
        }
        vTaskDelay(10000);
    }
}


void low_task(void *pvParameters)
{
    uint32_t low_task_num = 0;
    
    while (1)
    {
        printf("low_task 获取信号量\r\n");
        xSemaphoreTake(MutexSemaphore, portMAX_DELAY);       /* 获取计数型信号量 */
        printf("low_task 获取成功\r\n");
        for (low_task_num=0; low_task_num<5; low_task_num++)
        {
            printf("low_task 正在运行\r\n");
            delay_ms(1000);                              /* 模拟运行,不触发任务调度 */
        }
        printf("low_task 释放信号量\r\n");
        xSemaphoreGive(MutexSemaphore);                      /* 释放计数型信号量 */
        vTaskDelay(1000);
	}
}

实验结果 :

总结来说 

         FreeRTOS中的互斥信号量通过优先级继承机制有效地减少了优先级翻转的影响,从而提高了系统的实时性和响应性。这一机制使得低优先级任务在持有关键资源时,其优先级会被临时提升,以便尽快释放资源给高优先级任务,从而保证高优先级任务能尽快获得资源,减少不必要的延迟。

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

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

相关文章

react | 自学笔记 | 持续更新

React自学速学笔记 数据单向流动事件为什么上述例子&#xff0c;是onClick{()>shoot("goal!")}而不是onClick{shoot("goal")}?event对象 条件渲染if方法&&?: 三元表达式 纯小白自学笔记&#xff0c;有不对的欢迎指正。 数据单向流动 单向流动…

如何确保光伏电站EPC施工的质量

说到保证EPC施工的质量&#xff0c;我们得先了解什么是EPC施工&#xff0c;是指&#xff1a;指总承包商按照合同约定&#xff0c;承担工程项目的设计、采购、施工等工作&#xff0c;并对工程的质量、安全、工期和造价全面负责。 EPC施工还有几个特点&#xff1a; 一体化服务&…

单片机毕业设计基于stm32的蔬菜大棚智能监控系统设计

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP…

2.2.3 UDP的可靠传输协议QUIC 2

udp可靠传输 kcp协议 网络通畅下&#xff0c;kcp比tcp慢 这里直接看课件图片&#xff0c; 延迟ack比非延迟减少应答包数量&#xff0c;但是慢 kcp 讲解 kan代码ikcp.c 按照readme指南编译一下&#xff01;&#xff01; mkdir build cd build cmake .. make第一遍报错&#xf…

ant-design-vue中实现a-tree树形控件父子关联选中过滤的算法

在使用ant-design-vue的框架时&#xff0c;a-tree是比较常用的组件&#xff0c;比较适合处理树形结构的数据。 但是在与后台数据进行授权交互时&#xff0c;就不友好了。 在原生官方文档的例子中&#xff0c;若子项被勾选&#xff0c;则父级节点会被关联勾选&#xff0c;但这勾…

【堆的应用--C语言版】

前面一节我们都已将堆的结构&#xff08;顺序存储&#xff09;已经实现&#xff0c;对树的相关概念以及知识做了一定的了解。其中我们在实现删除操作和插入操作的时候&#xff0c;我们还同时实现了建大堆&#xff08;小堆&#xff09;的向上&#xff08;下&#xff09;调整算法…

【CSS in Depth 2 精译_024】4.2 弹性子元素的大小

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

PyInstaller问题解决 onnxruntime-gpu 使用GPU和CUDA加速模型推理

前言 在模型推理时&#xff0c;需要使用GPU加速&#xff0c;相关的CUDA和CUDNN安装好后&#xff0c;通过onnxruntime-gpu实现。 直接运行python程序是正常使用GPU的&#xff0c;如果使用PyInstaller将.py文件打包为.exe&#xff0c;发现只能使用CPU推理了。 本文分析这个问题…

TL-Tomcat中长连接的底层源码原理实现

长连接&#xff1a;浏览器告诉tomcat不要将请求关掉。 如果不是长连接&#xff0c;tomcat响应后会告诉浏览器把这个连接关掉。 tomcat中有一个缓冲区 如果发送大批量数据后 又不处理 那么会堆积缓冲区 后面的请求会越来越慢。

Java架构师未来篇大模型

目录 1. 大模型的定义2 大模型相关概念区分3 大模型的发展历程4. 大模型的特点5 大模型的分类6 大模型的泛化与微调7 大模型岗位需求8 理解大模型8.1 生活中的比喻8.2 大模型的定义9 大模型工作9.1 数据的积累9.2 模型的训练9.3 预测和应用10 大模型的实际应用10.1 语言处理10.…

240907-Gradio插入Mermaid流程图并自适应浏览器高度

A. 最终效果 B. 示例代码 import gradio as grmermaid_code """ <iframe srcdoc <!DOCTYPE html> <html><head><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width" />…

C++初阶:STL详解(一)——string类

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 1.为什么会有string类 C 语言中&#xff0c…

Nodejs中使用Minio

Minio 安装Minio MinIO下载 下载完&#xff0c;服务端和客户端后&#xff0c;最好像我这样做&#xff0c;去分一下路径。 安装完后&#xff0c;进入bin目录输入以下指令&#xff1a; # 设置账户 setx MINIO_ROOT_USER admin# 设置密码 setx MINIO_ROOT_PASSWORD password# …

高效办公必备!图片转PDF功能,让工作更轻松

在数字化时代&#xff0c;将图片转换为PDF格式是一项非常实用的技能&#xff1b;无论是在工作、学习还是生活中&#xff0c;我们都可能遇到需要将图片转化为PDF格式的情况&#xff1b;今天通过这篇文章给大家分享四款好用的图片转pdf 的工具&#xff1a; 第一款&#xff1a;福…

flutter开发实战-flutter web加载html及HtmlElementView的使用

flutter开发实战-flutter web加载html及HtmlElementView的web控件 HtmlElementView 是 Flutter 中用于嵌入 HTML 内容的 widget。这个 widget 允许你将一个 HTML 元素嵌入到 Flutter 应用中。 一、HtmlElementView基本使用 在工程的pubspec.yaml中引入插件 HtmlElementView…

多波束EM2040D以及POSMV使用记录

多波束EM2040D采集软件SIS4.3升级到SIS5.11之后&#xff0c;我们碰到了很多问题&#xff0c;现在将问题和解决过程记录一下。 1、SIS5软件打不开 SIS5软件打不开&#xff0c;报KSlSMainApp has stopped working弹框。 ​ 判断是电脑问题&#xff0c;更新最新win10系统&#…

ue5 伤害插件

主角或敌人都能用的插件&#xff0c;复用性很高 首先创建以下插件、接口、类型文件 两个枚举中的参数名称&#xff0c;E_DamageResponse区分是各个伤害后的反应&#xff0c;比如不同伤害造成的动画或粒子特效等的不同&#xff0c;E_DamageType是伤害类型&#xff0c;有各种伤害…

【网络安全】空字节绕过:URL回调+XSS+SQL绕WAF

未经许可,不得转载。 文章目录 空字节URL回调XSSSQL空字节 \0,也称为null字节,是一个值为零的特殊字符。在编程中,通常用来表示字符串的结束。攻击者可以利用null字节注入来绕过一些验证或过滤机制。 以下三个漏洞,空字节功不可没。 URL回调 密码重置功能,发起请求后…

【牛站 / USACO2007】

题目 思路 离散化&#xff08;降低空间复杂度&#xff09; 点的编号 ∈ [ 1 , 1000 ] &#xff0c;但是点的个数最多为 2 ⋅ T ∈ [ 4 , 200 ] 点的编号 \in [1, 1000]&#xff0c;但是点的个数最多为 2 \cdot T \in[4, 200] 点的编号∈[1,1000]&#xff0c;但是点的个数最多为…

【NLP】大模型长文本处理技术与GLM-4-Plus评测

本文将介绍Transformer模型在处理长文本数据时所采用的关键技术&#xff0c;特别是旋转位置编码&#xff08;RoPE&#xff09;和Flash Attention机制。 此外&#xff0c;本文介绍GLM系列模型&#xff0c;特别是最新发布的GLM-4-Plus模型。我们将通过实际的评测方法和结果&…