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

Freertos任务切换

一、操作系统进行任务切换的时机:

在这里插入图片描述采用信号量实现任务的互斥:
在这里插入图片描述

二、FreeRTOS 任务切换场合

PendSV 中断的时候提到了上下文(任务)切换被触发的场合:
● 可以执行一个系统调用
● 系统滴答定时器(SysTick)中断。

1、执行系统调用
执行系统调用就是执行 FreeRTOS系统提供的相关API函数,比如任务切换函数 taskYIELD(),
FreeRTOS 有些 API 函数也会调用函数 taskYIELD(),这些 API 函数都会导致任务切换,这些 API 函数和任务切换函数 taskYIELD()都统称为系统调用。

在这里插入图片描述
2、系统滴答定时器(SysTick)中断
在这里插入图片描述(1)、关闭中断
(2)、通过向中断控制和壮态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中断。这样就可以在 PendSV 中断服务函数中进行任务切换了。
(3)、打开中断。

在这里插入图片描述
在这里插入图片描述

三、查找下一个要运行的任务

在这里插入图片描述
在这里插入图片描述
(1)、如果调度器挂起那就不能进行任务切换。
(2)、调用函数 taskSELECT_HIGHEST_PRIORITY_TASK()获取下一个要运行的任务。
taskSELECT_HIGHEST_PRIORITY_TASK()本质上是一个宏,在 tasks.c 中有定义。
FreeRTOS 中查找下一个要运行的任务有两种方法:一个是通用的方法,另外一个就是使用
硬件的方法,这个在我们讲解 FreeRTOSCofnig.h 文件的时候就提到过了,至于选择哪种方法通
过宏 configUSE_PORT_OPTIMISED_TASK_SELECTION 来决定的。当这个宏为 1 的时候就使
用硬件的方法,否则的话就是使用通用的方法
在这里插入图片描述

四、任务的状态

在 FreeRTOS 中,当一个任务就绪后会自动插入就绪列表。
任务状态和就绪列表的概念
FreeRTOS 中的任务有多种状态,如就绪(Ready)、运行(Running)、阻塞(Blocked)和挂起(Suspended)。就绪状态的任务是已经准备好运行,等待调度器分配 CPU 时间来执行。就绪列表是一个数据结构,用于保存所有处于就绪状态的任务。
调度器会从就绪列表中选择一个任务来运行,这个选择过程是基于调度算法的,比如抢占式优先级调度算法,它会选择优先级最高的就绪任务来运行。
任务就绪的触发机制和插入过程
当一个任务创建成功并且其状态变为就绪时,例如任务创建函数xTaskCreate创建一个任务后,如果任务的初始状态是就绪(没有被阻塞或挂起),它会被自动插入就绪列表。
另外,当一个任务从阻塞状态(如等待一个信号量、消息队列或者定时器超时等情况)恢复到就绪状态时,系统也会自动将该任务插入就绪列表。这个过程是由 FreeRTOS 的内核机制来处理的,对于开发者来说是透明的。例如,一个任务因为等待一个信号量而阻塞,当信号量被释放后,等待该信号量的任务就会从阻塞状态转换为就绪状态,然后自动插入就绪列表,等待调度器调度运行。
所以,FreeRTOS 很好地管理了任务的状态转换和就绪列表的维护,确保就绪任务能够按照调度策略有机会得到执行。

五、Freertos时间片调度

FreeRTOS 支持多个任务同时拥有一个优先级,这些任务的调度是一个值得考虑的问题。在 FreeRTOS 中允许一个任务运行一个时间片(一个时钟节拍的长度)后让出 CPU 的使用权,让拥有同优先级的下一个任务运行,至于下一个要运行哪个任务?FreeRTOS 中的这种调度方法就是时间片调度。展示了运行在同一优先级下的执行时间图,在优先级 N 下有 3 个就绪的任务。
在这里插入图片描述
1、任务 3 正在运行。
2、这时一个时钟节拍中断(滴答定时器中断)发生,任务 3 的时间片用完,但是任务 3 还
没有执行完。
3、FreeRTOS 将任务切换到任务 1,任务 1 是优先级 N 下的下一个就绪任务。
4、任务 1 连续运行至时间片用完。
5、任务 3 再次获取到 CPU 使用权,接着运行。
6、任务 3 运行完成,调用任务切换函数 portYIELD()强行进行任务切换放弃剩余的时间片,
从而使优先级 N 下的下一个就绪的任务运行。
7、FreeRTOS 切换到任务 1。
8、任务 1 执行完其时间片。
要使用时间片调度的话宏 configUSE_PREEMPTION 和宏 configUSE_TIME_SLICING 必须
为 1。时间片的长度由宏 configTICK_RATE_HZ 来确定,一个时间片的长度就是滴答定时器的
中断周期,比如本教程中 configTICK_RATE_HZ 为 1000,那么一个时间片的长度就是 1ms。时
间片调度发生在滴答定时器的中断服务函数中,前面讲解滴答定时器中断服务函数的时候说了
在中断服务函数 SysTick_Handler()中会调用 FreeRTOS 的 API 函数 xPortSysTickHandler(),而函
数 xPortSysTickHandler() 会 引 发 任 务 调 度 , 但 是 这 个 任 务 调 度 是 有 条 件 的 , 函 数
xPortSysTickHandler()如下:
在这里插入图片描述
上述代码中红色部分表明只有函数 xTaskIncrementTick()的返回值不为 pdFALSE 的时候就
会进行任务调度!查看函数 xTaskIncrementTick()会发现有如下条件编译语句:
在这里插入图片描述
(1)、当宏 configUSE_PREEMPTION 和宏 configUSE_PREEMPTION 都为 1 的时候下面的
代码才会编译。所以要想使用时间片调度的话这这两个宏都必须为 1,缺一不可!
(2)、判断当前任务所对应的优先级下是否还有其他的任务。
(3)、如果当前任务所对应的任务优先级下还有其他的任务那么就返回 pdTRUE。
从上面的代码可以看出,如果当前任务所对应的优先级下有其他的任务存在,那么函数
xTaskIncrementTick() 就 会 返 回 pdTURE , 由 于 函 数 返 回 值 为 pdTURE 因 此 函 数
xPortSysTickHandler()就会进行一次任务切换。

五、Freertos 查找watchdog 卡在哪个任务

在vTaskSwitchContext函数中
在taskSELECT_HIGHEST_PRIORITY_TASK()后面
点灯 uxTopReadyPriority //可以点最后一个任务切到哪里去
再配合各个中断的位置点灯

六、可重入函数

如果一个函数可以从多个任务调用,或者从任务和中断调用是安全的,那么这个函数就是“可重入的”。可重入函数被称为“线程安全的”,因为它们可以从多个线程访问,而不会有数据或逻辑操作损坏的风险。
每个任务维护自己的堆栈和自己的处理器(硬件)寄存器集。如果函数不访问存储在堆栈上或保存在寄存器中的数据以外的任何数据,那么函数是可重入的,并且是线程安全的。

不可重入的,使用了全局变量,用了static修饰,保存在数据段上。每个去访问的任务访问到的都是同一份。都有可能被覆盖的风险。
在这里插入图片描述
数据类型参考:在这里插入图片描述


http://www.mrgr.cn/news/79772.html

相关文章:

  • 为什么按需学习效率更高?
  • TCP 2
  • qwen2.5 模型JSON格式化输出案例
  • VMware Workstation Pro 17 下载 以及 安装 Ubuntu 20.04.6 Ubuntu 启用 root 登录
  • UnityShaderLab-实现沿y轴溶解效果
  • 【数据结构】基数排序的原理及实现
  • Flask使用长连接(Connection会失效)、http的keep-alive、webSocket。---GPU的CUDA会内存不足报错
  • 开启第二阶段---蓝桥杯
  • 红日靶场vulnstack 4靶机的测试报告[细节](一)
  • uniapp-内部项目使用文档
  • C语言单元总结
  • String【Redis对象篇】
  • day10性能测试(2)——Jmeter
  • 【LeetCode每日一题】LeetCode 209.长度最小的子数组
  • java全栈day13-后端Web实战2
  • Pytest测试用例使用小结
  • 动态量化和静态量化
  • 【VUE2】纯前端播放海康视频录像回放,视频格式为rtsp格式,插件使用海康视频插件[1.5.4版本]
  • 作业Day1:思维导图、堆区申请空间并释放
  • Pointpillars模型转onnx