在本章节中,我们会涉及以下内容:
- FreeRTOS调度任务调度器
- FreeRTOS的任务调度方式
- FreeRTOS的四种任务状态
4.1 任务调度器和任务调度方式
那么什么是任务调度器呢?任务调度器就是使用相关的调度算法来决定当前需要执行的哪个任务。而我们的FreeRTOS一共支持三种任务调度方式。
- 抢占式调度 :主要是针对优先级不同的任务,每一个任务都有一个任务优先级,优先级高的任务可以抢占低优先级的任务的CPU使用权。
- 时间片调度 :主要针对相同优先级的任务,当多个任务的优先级相同时,任务调度器会在每个时钟节拍到来的时候切换任务。
- 协程式调度 :其实就是轮询,当前执行任务将会一直运行,同时高优先级的任务不会抢占低优先级任务。FreeRTOS现在虽然还在支持,但官方已经明确表示不再更新协程式调度。
4.1.1 抢占式调度过程
我们以下图来讲解:

运行过程如下:
- 首先Task1在运行中,在这个过程中Task2就绪了,在抢占式调度器的作用下,由于Task2的优先级更高,Task2会抢占Task1的运行。
- Task2运行过程中,Task3就绪了,在抢占式调度器的作用下,由于Task3的优先级更高,Task3会抢占Task2的运行。
- Task3运行过程中,Task3阻塞了(系统延时或者等待信号等),此时就绪中,优先级最高的任务Task2执行。
- Task3阻塞解除了(延时到了或者接收到信号量),此时Task3恢复到就绪态中,抢占Task2的运行。
总结:
- 高优先级任务,优先执行。
- 高优先级任务不停止,低优先级任务无法执行。
- 被抢占的任务将会进去就绪态。
4.1.2 时间片调度过程
那么问题来了,什么是时间片呢,时间片由什么决定呢?同等优先级任务轮流享有相同的CPU时间,叫做时间片,在FreeRTOS中,一个时间片等于SysTick中断周期。而在我们的FreeRTOSConfig.h中的configTICK_RATE_HZ这个宏,就是决定时间片的sysTick频率,同样我们可以在CubeMX中设置。

运行过程如下:
- 首先Task1运行完一个时间片后,切换至Task2运行。
- Task2运行完一个时间片后,切换至Task3运行。
- Task3运行过程中(还不到一个时间片),Task3阻塞了(系统延时或者等待信号量等),此时直接切换到下一个任务Task1执行。
- Task1运行完一个时间片后,切换至Task2运行。
总结:
- 同等优先级任务,轮流执行。
- 一个时间片大小,取决滴答定时器中断周期。
- 没有用完的时间片不会再使用,任务Task3下次得到执行时间还是按照一个时间片的时钟节拍运行。
4.2 四种任务状态与相互转换
4.2.1、四种任务状态
FreeRTOS 系统中的每一任务都有多种运行状态。系统初始化完成后,创建的任务就可 以在系统中竞争一定的资源,由内核进行调度。
任务状态通常分为以下四种:
- 就绪(Ready):该任务在就绪列表中,就绪的任务已经具备执行的能力,只等 待调度器进行调度,新创建的任务会初始化为就绪态。
- 运行(Running):该状态表明任务正在执行,此时它占用处理器,FreeRTOS 调 度器选择运行的永远是处于最高优先级的就绪态任务,当任务被运行的一刻,它 的任务状态就变成了运行态。
- 阻塞(Blocked):如果任务当前正在等待某个时序或外部中断,我们就说这个任 务处于阻塞状态,该任务不在就绪列表中。包含任务被挂起、任务被延时、任务 正在等待信号量、读写队列或者等待读写事件等。
- 挂起态(Suspended):处于挂起态的任务对调度器而言是不可见的,让一个任务进 入挂起状态的唯一办法就是调用 vTaskSuspend()函数;而 把一个挂起 状态 的任 务 恢复的 唯 一 途 径 就 是 调 用 vTaskResume() 或vTaskResumeFromISR()函 数,我们可以这么理解挂起态与阻塞态的区别,当任务有较长的时间不允许运行 的时候,我们可以挂起任务,这样子调度器就不会管这个任务的任何信息,直到 我们调用恢复任务的 API 函数;而任务处于阻塞态的时候,系统还需要判断阻塞 态的任务是否超时,是否可以解除阻塞。
4.2.2、四种任务状态之间的转换关系

- 创建任务→就绪态(Ready):任务创建完成后进入就绪态,表明任务已 准备就绪,随时可以运行,只等待调度器进行调度。
- 就绪态→运行态(Running):发生任务切换时,就绪列表中最高优先级 的任务被执行,从而进入运行态。
- 运行态→就绪态:有更高优先级任务创建或者恢复后,会发生任务调度, 此刻就绪列表中最高优先级任务变为运行态,那么原先运行的任务由运行态变为就绪态, 依然在就绪列表中,等待最高优先级的任务运行完毕继续运行原来的任务(此处可以看做 是 CPU 使用权被更高优先级的任务抢占了)。
- 运行态→阻塞态(Blocked):正在运行的任务发生阻塞(挂起、延时、 读信号量等待)时,该任务会从就绪列表中删除,任务状态由运行态变成阻塞态,然后发 生任务切换,运行就绪列表中当前最高优先级任务。
- 阻塞态→就绪态:阻塞的任务被恢复后(任务恢复、延时时间超时、读 信号量超时或读到信号量等),此时被恢复的任务会被加入就绪列表,从而由阻塞态变成 就绪态;如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换, 将该任务将再次转换任务状态,由就绪态变成运行态。
- (6)(7)(8)就绪态、阻塞态、运行态→挂起态(Suspended):任务可以通 过调用 vTaskSuspend() API 函数都可以将处于任何状态的任务挂起,被挂起的任务得不到 CPU 的使用权,也不会参与调度,除非它从挂起态中解除。
- 挂起态→就绪态:把 一 个 挂 起 状态 的 任 务 恢复的 唯 一 途 径 就 是 调 用 vTaskResume() 或 vTaskResumeFromISR() API 函数,如果此时被恢复任务的优先级高 于正在运行任务的优先级,则会发生任务切换,将该任务将再次转换任务状态,由就绪态 变成运行态。