当前位置: 首页 > news >正文

FreeRTOS内部机制理解(任务调度机制)(三)

文章目录

  • 摘要
  • 三、任务调度机制
    • 3.1 解释创建同优先级任务执行顺序问题
    • 3.2 空闲任务和栈的另外一点疑惑
    • 3.3 通过链表继续深入理解调度机制
    • 3.4



摘要

任务调度FreeRTOS源码

三、任务调度机制

3.1 解释创建同优先级任务执行顺序问题

![[Pasted image 20250825205602.png]]

这里解释了为什么我们在创建多个相同任务的时候,最先执行的总是最后一个创建的。这是因为后续创建的任务都是小于等于最新的创建任务,因此直接就执行条件里面的,并且还会将最新的任务TCB赋值给当前的任务TCB,所以就解释了为什么总是执行最后创建的那一个任务。秒!!!!!!!!!!!!!!!

3.2 空闲任务和栈的另外一点疑惑

在就绪任务链表中还有一个是空闲任务。

该空闲任务主要是一些清理工作,如果一些任务自杀了,那么这个自杀任务的栈空间需要清空,但是由于任务自杀了没办法在清空栈了,因此空闲任务就起到了核心的作用,清理作用。

![[Pasted image 20250825212734.png]]

![[Pasted image 20250825212853.png]]

通过这两个图可以深入理解同优先级的任务创建过程,并且在都是优先级为0的时候会出现一些奇怪的现象。

由于我们的调度器会创建一个空闲任务,并且这个空闲任务的优先级是0,因此我们根据下属代码可以知道

![[Pasted image 20250825205602.png]]

调度器是最后创建空闲任务,那么由于都是0优先级,因此pxCurrentTCB指向的任务是就是空闲任务,这样就不会先执行Task3,反而会是限制性空闲任务,然后在接着执行Task1,就会出现跟第一个图不一样的结果,因为第一个图中我们创建的三个任务都优先级1,而空闲任务的优先级是0,因此肯定是最后执行空闲任务的,先执行我们创建的任务,又因为优先级是一样的,那么根据上述代码可知pxCurrentTCB指向的任务是就是Task3任务。这就是差别所在,所以我们在开发时候还是要任务优先级是0的时候空闲任务在初始阶段会带来的影响。

几个栈空间的说明:

1、在汇编函数中需要设置一个栈空间,那么这个栈空间就是给main函数使用以及中断函数使用。

2、而我们创建函数的时候也有一个栈空间,那么这个栈空间就是指给这个创建函数的栈使用(如果没有使用堆,那么这个栈就是包含了大的栈空间,如果使用堆空间,那么就有点区别。但是整体的思路是不改变的。)。

3.3 通过链表继续深入理解调度机制

  • 可抢占:高优先级任务先运行

  • 时间片轮转:同优先级任务轮流执行

  • 空闲任务礼让:如果同是优先级0的其他就绪任务,空闲任务礼让。空闲任务主动放弃一次运行机会。

首先看空闲任务是怎么执行。

![[Pasted image 20250825213850.png]]

空闲任务礼让:具体来说就是空闲任务要在所有任务执行一次以后再说执行。

以空闲任务和其他任务优先级都是0来说,我们经过上面的知道,都是0的时候,会先执行这个空闲任务,但是执行到taskYIELD()的时候,空闲任务会暂停执行,产生一次主动调度,这个过程就是主动礼让。 然后开始执行Task任务,最后执行完所有的TASK任务以后开始执行这个空闲任务,并且还是接着上一次被中断的地方执行,然后新一轮循环。

而等到在下一次进来这个空闲任务的时候,又会满足这个条件,那么就继续重复上述操作,主动发起一次调度,产生一次礼让,重复上述操作。

程序中大于1中的这个1,值得就是空闲任务,因为不管怎么这个就绪任务链表一定有一个任务那就是空闲任务,因此是需要大于1。

![[Pasted image 20250825214124.png]]

![[Pasted image 20250825215202.png]]

  • 主动放弃 vTaskDelay 或者是队列没数据就主动休眠了

  • 被动放弃 GPIO按键中断来了唤醒了高优先级任务

思考:

存在:不抢占、不礼让,轮流执行 所有任务优先级都是0,

运行空闲任务,只是起到清理作用,然后继续礼让。

并且执行到任务1就不会继续执行了,

configUSE_PREEMPTION 表示是否配置为抢占式调度

configUSE_TIME_SLICING 表示配置为轮流执行

configIDLE_SHOULD_YIELD 表示是否配置为礼让

不开抢占,实际上也轮转不了,空闲任务也必须礼让。

![[Pasted image 20250825220517.png]]

所以在执行空闲任务一会以后,马上就执行Task1。

![[Pasted image 20250825220032.png]]

xSwitchRequired:表示的是执行时间片轮询的方式进行任务切换。

但是由于我们配置为不抢占,也就是configUSE_PREEMPTION == 0,所以就不能执行,这样我们就不能进行轮询执行,也就是说我们没有设置抢占调度,那么连轮流执行的机会都不会,所以最终呈现出来的就是一直执行Task1。

![[Pasted image 20250825220859.png]]

为什么这样,这是因为FreeRTOS的作者这样设计的,没有为什么,如果不是抢占式调度,那么就不是FreeRTOS了,那为什么还需要使用FreeRTOS,不就没有意思了。

渐渐地就有点明白FreeRTOS的源码了,但是还是需要很长的路。

并且在上述情况下,只有TAsk1主动放弃,才能执行Task2,并且Task2也是一直执行,就跟Task1的原因一样。

主动放弃以后我们空闲任务才能起到真正的作用,那就是进空闲任务执行的第一句话,释放空间。

3.4

如果觉得我的内容对您有帮助,希望不要吝啬您的赞和关注,您的赞和关注是我更新优质内容的最大动力。



专栏介绍

《嵌入式通信协议解析专栏》
《PID算法专栏》
《C语言指针专栏》
《单片机嵌入式软件相关知识》
《FreeRTOS源码理解专栏》
《嵌入式软件分层架构的设计原理与实践验证》



文章源码获取方式:
如果您对本文的源码感兴趣,欢迎在评论区留下您的邮箱地址。我会在空闲时间整理相关代码,并通过邮件发送给您。由于个人时间有限,发送可能会有一定延迟,请您耐心等待。同时,建议您在评论时注明具体的需求或问题,以便我更好地为您提供针对性的帮助。

【版权声明】
本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议。这意味着您可以自由地共享(复制、分发)和改编(修改、转换)本文内容,但必须遵守以下条件:
署名:您必须注明原作者(即本文博主)的姓名,并提供指向原文的链接。
相同方式共享:如果您基于本文创作了新的内容,必须使用相同的 CC 4.0 BY-SA 协议进行发布。

感谢您的理解与支持!如果您有任何疑问或需要进一步协助,请随时在评论区留言,笔者一定知无不言,言无不尽。

http://www.dtcms.com/a/354129.html

相关文章:

  • opencv学习笔记
  • 基于 Docker Compose 的若依多服务一键部署java项目实践
  • 【深度学习-Day 44】GRU详解:LSTM的优雅继任者?门控循环单元原理与PyTorch实战
  • sparksql的transform如何使用
  • 8.27 网格memo
  • HTTP 头
  • Go 1.25新特性之容器感知功能详解
  • 【C++语法篇】:函数
  • 超越ChatBI!深度解析衡石HENGSHI SENSE 6.0如何实现全流程AI赋能
  • 第二阶段WinFrom-7:文件操作补充,泛型复习,协变和逆变
  • Python LangChain RAG从入门到项目实战09.:LangChain 中的 Retriever(检索器)
  • buuctf——web刷题第5页
  • Vue2 基础用法
  • CVPR深度学习研究指南:特征提取模块仍是论文创新难点
  • 吴恩达机器学习作业二:线性可分逻辑回归
  • CMake构建学习笔记21-通用的CMake构建脚本
  • Liunx内核驱动
  • Java中StringBuilder原理以及使用
  • D4145低功耗GFCI接地故障控制芯片介绍
  • 题目—移除元素
  • 作业帮,途虎养车,得物,途游游戏,三七互娱,汤臣倍健,游卡,快手26届秋招内推
  • JUC多线程个人笔记
  • 【DC工具GUI入门】
  • APP测试全流程以及测试点
  • 【开题答辩全过程】以 基于SpringBoot的流浪动物领养系统的设计与实现 为例,包含答辩的问题和答案
  • 从Java到Go:初遇Go语言的震撼体验
  • 力扣 30 天 JavaScript 挑战 第41天 (第十二题)对异步操作,promise,async/await有了更深理解
  • 【Linux实时内核机制】ww_rt_mutex 的contending_lock异常问题
  • android/java中主线程和子线程的详解
  • Nano Banana揭秘:Google Gemini 2.5 Flash Image正式发布 | AI图像编辑新时代