写在最前
由于工作需要,需要开始学习freertos的相关知识,本专题主要记录freertos的相关内容
参考:
https://www.bilibili.com/video/BV19g411p7UT 正点原子视频
1. 任务调度状态
1.1 四种调度状态
如上图,freertos总共有4种状态
-
运行态
:正在执行的任务,该任务就处于运行态,注意在STM32中,同一时间仅一个任务处于运行态 -
就绪态
:如果该任务已经能够被执行,但当前还未被执行,那么该任务处于就绪态 -
阻塞态
:如果一个任务因延时或等待外部事件发生,那么这个任务就处于阻塞态 -
挂起态
:类似暂停,调用函数vTaskSuspend()
进入挂起态,需要调用解挂函数vTaskResume()
才可以进入就绪态
仔细看上图我们可以发现:
- 只有
就绪态
可以转变成运行态
,其他任务的状态想运行,必须先变成就绪态
- 其中
就绪台
和挂起态
,运行态
和就绪态
可以相互转换
ps:讲到这,我发现这和书本上讲的操作系统的进程这个概念非常像,状态也非常像,如下图,RTOS的任务就类似于我们学的进程吧
1.2 状态转换
-
创建任务→就绪态
(Ready):任务创建完成后进入就绪态,表明任务已准备就绪,随时可以运行,只等待调度器进行调度。 -
就绪态→运行态
(Running):发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态。 -
运行态→就绪态
:有更高优先级任务创建或者恢复后,会发生任务调度,此刻就绪列表中最高优先级任务变为运行态,那么原先运行的任务由运行态变为就绪态,依然在就绪列表中,等待最高优先级的任务运行完毕继续运行原来的任务。 -
运行态→阻塞态
(Blocked):**正在运行的任务发生阻塞(挂起、延时、读信号量等待)**时,该任务会从就绪列表中删除,任务状态由运行态变成阻塞态,然后发生任务切换,运行就绪列表中当前最高优先级任务。 -
阻塞态→就绪态
:阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的任务会被加入就绪列表,从而由阻塞态变成就绪态;如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务将再次转换任务状态,由就绪态变成运行态。 -
就绪态、阻塞态、运行态→挂起态
(Suspended):任务可以通过调用vTaskSuspend() API 函数都可以将处于任何状态的任务挂起,被挂起的任务得不到CPU的使用权,也不会参与调度,除非它从挂起态中解除。 -
挂起态→就绪态
:把 一 个 挂 起 状态 的 任 务 恢复的 唯 一 途 径 就 是 调 用 vTaskResume() 或vTaskResumeFromISR() API 函数,如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务将再次转换任务状态,由就绪态变成运行态。
1.3 任务状态列表
FreeRTOS中无非就四种状态,运行态
,就绪态
、阻塞态
、挂起态
这四种状态中,除了运行态
,其他三种任务状态的任务都有其对应的任务状态列表
每个列表都是一个32位的变量,当某个位置1时,代表所对应的优先级就绪列表有任务存在
1.4 任务状态例子
不同优先级
假设我们创建了三个任务分别为task1
, task2
, task3
,优先级分别为1,2,3
此时就绪列表中task3
放在最前,task2
,task1
紧随其后
调度器总是在所有处于就绪列表的任务中,选择具有最高优先级的任务来执行
相同优先级
假设我们创建了三个任务分别为task1
, task2
, task3
,优先级都为3
此时task1
, task2
, task3
按照时间片轮流执行
2. 任务调度方式(算法)
和进程调度算法一样,freertos也有任务调度算法
2.1 调度器
FreeRTOS中提供的任务调度器是基于优先级的抢占式调度:在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的。
调度器就是使用相关的调度算法来决定当前需要执行的任务。所有的调度器有一些共同的特性:
- 调度器可以区分就绪态任务和挂起态任务(由于延迟,信号量等待,事件组等待等原因而使得任务被挂起)。
- 调度器可以选择就绪态中的一个任务,然后激活它(通过执行这个任务)。 当前正在执行的任务是运行态的任务。
freertos提供三种调度方式:
抢占式调度
:主要是针对优先级不同的任务,每个任务都有一个优先级,优先级高的任务可以抢占优先级低的任务。时间片调度
:主要针对优先级相同的任务,当多个任务的优先级相同时, 任务调度器会在每一次系统时钟节拍到的时候切换任务。协程式调度
:当前执行任务将会一直运行,同时高优先级的任务不会抢占低优先级任务FreeRTOS现在虽然还支持,但是官方已经表示不再更新协程式调度,由于这种方式就类似于裸机的任务调度方式了,实时性较差,因此这种方式被舍弃
2.2 抢占式调度
我们通过一个例子来讲解抢占式调度的原理,如下图:
运行前提:
- 创建三个任务:
Task1
、Task2
、Task3
Task1
、Task2
、Task3
的优先级分别为1、2、3;在FreeRTOS中任务设置的数值越大,优先级越高,所以Task3的优先级最高
运行过程:
- 首先
Task1
在运行中,在这个过程中Task2
就绪了,在抢占式调度器的作用下Task2
会抢占Task1
的运行 Task2
运行过程中,Task3
就绪了,在抢占式调度器的作用下Task3
会抢占Task2
的运行Task3
运行过程中,Task3
阻塞了(系统延时或等待信号量等),此时就绪态中,优先级最高的任务Task2
执行Task3
阻塞解除了(延时到了或者接收到信号量),此时Task3
恢复到就绪态中,抢占TasK2
的运行
总结
- 高优先级任务,优先执行
- 高优先级任务不停止,低优先级任务无法执行
- 被抢占的任务将会进入就绪态
2.3 时间片调度
同等优先级任务轮流地享有相同的 CPU 时间(可设置), 叫时间片,在FreeRTOS中,一个时间片就等于SysTick 中断周期
运行前提:
- 创建三个任务:
Task1
、Task2
、Task3
Task1
、Task2
、Task3
的优先级均为1;即3个任务同等优先级
运行过程:
- 首先
Task1
运行完一个时间片后,切换至Task2
运行 Task2
运行完一个时间片后,切换至Task3
运行Task3
运行过程中(还不到一个时间片),Task3
阻塞了(系统延时或等待信号量等),此时直接切换到下一个任务Task1
Task1
运行完一个时间片后,切换至Task2运行
总结
- 同等优先级任务,轮流执行;时间片流转
- 一个时间片大小,取决为滴答定时器中断周期
- 注意没有用完的时间片不会再使用,下次任务Task3得到执行,还是按照一个时间片的时钟节拍运行