FreeRTOS任务调度(抢占式、协作式、时间片轮转)

任务调度

文章目录

  • 任务调度
  • 前言
  • 一、协作式
  • 二、时间片轮转
  • 三、抢占式
  • 总结


前言

FreeRTOS 是一个开源的实时操作系统,它支持多种调度策略,包括协作式(cooperative)和抢占式(preemptive)调度。

一、协作式

在协作式调度中,一旦一个任务开始执行,它将持续运行,直到它自己放弃 CPU 控制权为止。这通常发生在任务主动调用 task delay(等待时间片到期)、task yield(放弃剩余时间片)、或者进入阻塞状态(等待事件或资源)时。协作式调度简化了任务间共享资源的管理,因为开发者可以确保在没有明确放弃 CPU 控制权的情况下,任务不会被中断。但这种模式要求每个任务都必须定期放弃 CPU 控制权,否则可能导致系统响应性能下降。
协作式的调度方式,其本质上是任务在运行一段时间后,自己放弃CPU运行权,让其他任务运行。

在FreeRTOS里,是通过taskYIELD()这个函数实现放弃CPU的。一个典型的协作式任务是在while(1){}大循环的最后,调用taskYIELD()去主动放弃CPU;这时其他处于就绪态的最高优先级的任务才可能运行;如果其他任务都不在就绪状态,那么仍然回到taskYIELD()后面继续运行原来的任务。

在FreeRTOS里taskYIELD()是一种放弃CPU执行权的方法,还可以使用延时函数vTaskDelay,以及等待信号量、消息队列等等。
在这里插入图片描述
这里改成0是协作式
直接看代码

/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      4                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 */

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO      4                   /* 任务优先级 */
#define TASK3_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task3Task_Handler;  /* 任务句柄 */
void task3(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/


/**
 * @brief       FreeRTOS入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{
    
    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();
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )task1,                 /* 任务函数 */
                (const char*    )"task1",               /* 任务名称 */
                (uint16_t       )TASK1_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )TASK1_PRIO,            /* 任务优先级 */
                (TaskHandle_t*  )&Task1Task_Handler);   /* 任务句柄 */
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )task2,                 /* 任务函数 */
                (const char*    )"task2",               /* 任务名称 */
                (uint16_t       )TASK2_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )TASK2_PRIO,            /* 任务优先级 */
                (TaskHandle_t*  )&Task2Task_Handler);   /* 任务句柄 */
    /* 创建任务3 */
    xTaskCreate((TaskFunction_t )task3,                 /* 任务函数 */
                (const char*    )"task3",               /* 任务名称 */
                (uint16_t       )TASK3_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )TASK3_PRIO,            /* 任务优先级 */
                (TaskHandle_t*  )&Task3Task_Handler);   /* 任务句柄 */
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

/**
 * @brief       task1
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task1(void *pvParameters)
{
    uint32_t task1_num = 0;
    
    while (1)
    {
       printf("task1\r\n");
        HAL_Delay(100);
    }
}

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{
    uint32_t task2_num = 0;
    
    while (1)
    {
              printf("task2\r\n");
        HAL_Delay(200);
    }
}

/**
 * @brief       task3
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task3(void *pvParameters)
{
    uint8_t key = 0;
    
    while (1)
    {
              printf("task3\r\n");
        HAL_Delay(300);
    }
}

先来看这段代码的执行结果
在这里插入图片描述
只有task2在执行,task3和task2是相同优先级 但是task2任务先创建的,task2任务执行后没有放弃CPU使用权,所以其他任务没有机会执行。
这说明了协作式的调度,是需要任务自己放弃CPU的,否则其他任务不能得到运行机会。​
然后我们修改一下代码
在这里插入图片描述
可以看到task2执行完之后把cpu执行权释放了,然后这个时候task3开始执行,由于task3开始执行后没有释放CPU执行权所以,task2任务无法执行
在这里插入图片描述
然后我们在修改一下代码
在这里插入图片描述
可以看到task2和task3交替执行
在这里插入图片描述
可以发现,现在task02和task03都有执行,而task01没有执行。

这是因为task02在执行完后,通过taskYIELD();放弃了CPU;

此时task03和task01都有机会运行,但是task03优先级高,所以task03获得了运行机会;

task03运行完之后,也是通过taskYIELD();放弃了CPU,此时task02和task01有机会运行,但是task02优先级高,task02又获得了运行权。

这样循环执行,由于task01优先级低,它总是得不到运行机会。
如果想要所有任务都执行到,一种可行的方法是使用vTaskDelay指定放弃CPU的时间,如task02中放弃1000周期、tack03中放弃1000周期,那么当这两个任务都被挂起时,task01就获得了运行权。
我们修改一下代码
在这里插入图片描述
可以看到执行结果
在这里插入图片描述

二、时间片轮转

时间片轮转的调度方法,是让相同优先级的几个任务轮流运行,每个任务运行一个时间片,任务在时间片运行完之后,操作系统自动切换到下一个任务运行;在任务运行的时间片中,也可以提前让出CPU运行权,把它交给下一个任务运行(这一点和协作式类似)。
FreeRTOS的时间片固定为一个时钟节拍,由configTICK_RATE_HZ这个宏设置
在这里插入图片描述
把设置改回来,然后修改一下代码
在这里插入图片描述
在这里插入图片描述

可以看到执行结果,各任务都不主动放弃CPU。可以看到,虽然各个任务都没有主动放弃CPU执行权,但是同为高优先级的task02和task03,都得到了运行的机会;只有低优先级的task01没有执行到。这是因为操作系统对两个高优先级的任务使用了时间片轮转调度,轮流得到了执行。
关闭时间片轮转调度功能,即把configUSE_TIME_SLICING宏定义去除或定义为0:
在这里插入图片描述
执行结果如下图所示
在这里插入图片描述
task03又没有机会去执行了。

三、抢占式

抢占式调度允许操作系统根据优先级来决定哪个任务应当获得 CPU 控制权。当一个高优先级任务变为就绪状态时(例如,它正在等待的事件发生了),系统会中断当前运行的较低优先级任务,把 CPU 控制权交给高优先级任务。这确保了对紧急任务的快速响应。在这种模式下,任务不需要显式放弃 CPU 控制权,因为它们可以随时被更高优先级的任务抢占。

抢占式调度,是最高优先级的任务一旦就绪,总能得到CPU的执行权;它抢占了低优先级的运行机会。在抢占式调度系统中,总是运行最高优先级的任务。

抢占式调度的特点在于,可以使得一些需要实时运行的任务,能在较短的时间内获得CPU执行权,保证这些实时任务及时执行。

在FreeRTOS中,抢占式调度,与时间片轮转可以同时存在;当有高优先级任务就绪时,运行高优先级任务;当最高优先级的任务有好几个时,这几个任务可以以时间片轮转方式调度。
我们修改一下代码

在这里插入图片描述

低优先级的task01一直占用CPU,不会主动放弃执行权;task02执行一次,放弃500ms的执行权;task03执行一次,放弃1000ms执行权:
然后看一下结果
在这里插入图片描述

首先task02和task03执行时间片轮转,各执行了一次;然后它们都放弃了CPU执行权,task01得到了执行,在500ms内,它可以执行3次;

到500ms时,task02第一次延时时间到,恢复就绪态,task02抢占了CPU执行,执行完打印后,又进行延时放弃CPU;task01得到了执行;又执行了2次,过去了1000ms,这个时候task02和task03都有机会执行,进行了一次时间片轮转,然后又回到task01执行

到100ms时,task03第一次恢复就绪,task02第二次恢复就绪,都各执行了一遍;之后又让出CPU;task01得到了执行;然后一直循环。

总结

可以看出,开启了抢占式和时间片轮转两种调度算法时,高优先级的任务一旦就绪,就能抢占低优先级的CPU执行权;如果有两个同优先级的任务都可以运行,则它们之间是时间片轮转方式调度。抢占式调度和时间片轮转两种任务的切换方式,可以说是FreeRTOS系统最核心的功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

堆排序Java

思路 这个代码还不错 https://blog.csdn.net/weixin_51609435/article/details/122982075 就是从下往上进行调整 1. 如何将数组映射成树 对于下面这颗树,原来的数组是: 好,如果调整的话,我们第一个应该调整的是最下边&#x…

压缩文件隐写

1、伪加密 (1)zip伪加密 考点:winhex打开压缩包;搜索504b0102(注意不是文件头部;zip文件头部伪504b0304);从50开始,往后面数第9,10个字符为加密字符,将其设置为0000即可变为无加密状…

JAVAEE初阶第七节(中)——物理原理与TCP_IP

系列文章目录 JAVAEE初阶第七节(中)——物理原理与TCP_IP 文章目录 系列文章目录JAVAEE初阶第七节(中)——物理原理与TCP_IP 一.应用层重点协议)1. DNS2 .NAT3. NAT IP转换过程 4 .NAPT5. NAT技术的缺陷6. HTTP/HTTPS…

野火霸天虎V2学习记录

文章目录 嵌入式开发常识汇总1、嵌入式Linux和stm32之间的区别和联系2、stm32程序下载方式3、Keil5安装芯片包4、芯片封装种类5、STM32命名6、数据手册和参考手册7、什么是寄存器、寄存器映射和内存映射8、芯片引脚顺序9、stm32芯片里有什么10、存储器空间的划分11、如何理解寄…

如何部署Vue+Springboot项目

很多同学在项目上线的部署遇到困难,不懂得怎么部署项目,本文将会带大家手把手从前端部署、java部署来教会大家。 如果项目涉及到了docker相关中间件的环境配置,请参看:https://blog.csdn.net/weixin_73195042/article/details/13…

C#发送正文带图片带附件的邮件

1,开启服务,获取授权码。以QQ邮箱为例: 点击管理服务,进入账号与安全页面 2,相关设置参数,以QQ邮箱为例: 登录时,请在第三方客户端的密码输入框里面填入授权码进行验证。&#xff0…

解决 Ant Design Vue Upload 组件在苹果手机上只能拍照无法选择相册的问题

最近上线发现了这个问题&#xff0c;看别的文档改了很多属性也不行&#xff0c;发现element组件就可以&#xff0c;对比之后就知道问题所在。 原因&#xff1a; 默认情况下&#xff0c;iOS 设备会将 <input type"file"> 的 capture 属性设置为 true&#xff0…

[数据集][目标检测]电动车头盔佩戴检测数据集VOC+YOLO格式4235张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4235 标注数量(xml文件个数)&#xff1a;4235 标注数量(txt文件个数)&#xff1a;4235 标注…

python 正则表达式“.*”和“.*? ”的区别

“.*”和“.*? ”的区别 点号表示任意非换行符的字符&#xff0c;星号表示匹配它前面的字符0次或者任意多次。所以“.*”表示匹配一串任意长度的字符串任意次。这个时候必须在“.*”的前后加其他的符号来限定范围&#xff0c;否则得到的结果就是原来的整个字符串。 “.*? &…

基于SpringBoot校园快递代取系统

基于springbootvue实现的校园快递代取系统&#xff08;源码L文ppt&#xff09;4-049 3系统设计 3.1.1系统结构图 系统结构图可以把杂乱无章的模块按照设计者的思维方式进行调整排序&#xff0c;可以让设计者在之后的添加&#xff0c;修改程序内容…

基于SpringBoot框架和Flask的图片差异检测与展示系统

目录 1. 项目目标 2. 功能需求 &#xff08;1&#xff09;图片上传功能 &#xff08;2&#xff09;差异检测算法 &#xff08;3&#xff09;后端服务 &#xff08;4&#xff09;前端展示 &#xff08;5&#xff09;阿里云服务器存储 &#xff08;6&#xff09;数据库记…

Java:正则表达式 matches

文章目录 正则表达式作用基本用法小结代码 案例&#xff1a;校验用户输入的电话&#xff0c;邮箱&#xff0c;是否合法\\.是什么意思 黑马学习笔记 正则表达式 由一些特定的字符组成&#xff0c;代表的是一个规则 作用 用来校验数据格式是否合法在一段文本中查找满足要求的内…

Elasticsearch:无状态世界中的数据安全

作者&#xff1a;来自 Elastic Henning Andersen 在最近的博客文章中&#xff0c;我们宣布了支持 Elastic Cloud Serverless 产品的无状态架构。通过将持久性保证和复制卸载到对象存储&#xff08;例如 Amazon S3&#xff09;&#xff0c;我们获得了许多优势和简化。 从历史上…

Web3D 技术发展瓶颈在哪里?

Web3D 技术的发展瓶颈主要集中在以下几个方面&#xff1a; 1、性能和优化&#xff1a;尽管现代浏览器和硬件逐步提高了性能&#xff0c;但高质量的3D渲染仍可能导致性能瓶颈。特别是在移动设备上&#xff0c;图形渲染和计算可能会受到限制。建议合理控制好项目资源量&#xff…

实验记录 | 点云处理 | K-NN算法3种实现的性能比较

引言 K近邻&#xff08;K-Nearest Neighbors, KNN&#xff09;算法作为一种经典的无监督学习算法&#xff0c;在点云处理中的应用尤为广泛。它通过计算点与点之间的距离来寻找数据点的邻居&#xff0c;从而有效进行点云分类、聚类和特征提取。本菜在复现点云文章过程&#xff…

详解React setState调用原理和批量更新的过程

1. React setState 调用的原理 setState目录 1. React setState 调用的原理2. React setState 调用之后发生了什么&#xff1f;是同步还是异步&#xff1f;3. React中的setState批量更新的过程是什么&#xff1f; 具体的执行过程如下&#xff08;源码级解析&#xff09;&#x…

基于SpringBoot+Vue+MySQL的宿舍维修管理系统

系统展示 前台界面 管理员界面 维修员界面 学生界面 系统背景 在当今高校后勤管理的日益精细化与智能化背景下&#xff0c;宿舍维修管理系统作为提升校园生活品质、优化资源配置的关键环节&#xff0c;其重要性日益凸显。随着学生规模的扩大及住宿条件的不断提升&#xff0c;宿…

人机交互系统中的人脸讲话生成系统调研

《Human-Computer Interaction System: A Survey of Talking-Head Generation》 图片源&#xff1a;https://github.com/Yazdi9/Talking_Face_Avatar 目录 前言摘要一、背景介绍二、人机交互系统体系结构2.1. 语音模块2.2. 对话系统模块2.3. 人脸说话动作生成 三 人脸动作生成…

来啦| LVMH路威酩轩25届校招智鼎高潜人才思维能力测验高分攻略

路威酩轩香水化妆品(上海)有限公司是LVMH集团于2000年成立&#xff0c;负责集团旗下的部分香水化妆品品牌在中国的销售包括迪奥、娇兰、纪梵希、贝玲妃、玫珂菲、凯卓、帕尔马之水以及馥蕾诗等。作为目前全球最大的奢侈品集团LVMH 集团秉承悠久的历史&#xff0c;不断打破常规&…

【微处理器系统原理和应用设计第六讲】片上微处理器系统系统架构

一、概念辨析 首先来厘清以下概念&#xff1a;微处理器&#xff0c;微控制器&#xff0c;单片机&#xff0c;片上微处理器系统 &#xff08;1&#xff09;微处理器&#xff1a;即MPU&#xff08;Microprocessor Unit&#xff09;&#xff0c;微处理器是一种计算机的中央处理单…