FreeRTOS Kernel 允许多个 Task 并行,这里的 Task 有点类似于 Linux 的线程,然后 FreeRTOS Kernel 会对这些 Task 进行调度。目前 FreeRTOS Kernel 提供了三种调度算法,他们各有优劣可以根据实际情况选择对应的调度算法。

1. 状态

FreeRTOS-Kernel state

在 FreeRTOS 中 Task 一共有四种状态,分别为 ReadySupendedBlocked 以及 Runing

  1. Ready

    Ready 状态表示当前 Task 已经准备好啦,可以随时启动,但是 CPU 被其他 Task 占用需要等待

  2. Running

    Running 状态表示当前 Task 正在运行

  3. Blocked

    Block 状态表示当前 Task 进行同步操作正在等待事件触发

  4. Suspended

    Suspended 状态表示当前 Task 无法被调度,通过调用 vTaskSuspend() 函数进入这个状态,调用 xTaskResume 恢复到 Ready 状态

2. 调度算法选择

FreeRTOS-Kernel 的调度算法主要是通过两个变量来决定的,他们分别为:configUSE_PREEMPTION, configUSE_TIME_SLICING

Scheduling Algorithm Prioritized configUSE_PREEMPTION configUSE_TIME_SLICING
Preemptive With Time Slicing Yes 1 1
Preemptive Without Time Slicing Yes 1 0
Co-Operative No 0 Any

configUSE_PREEMPTION 表示是否启用抢占优先级,所谓抢占优先级是指当如果高优先级的 Task 处于 Ready 状态可以强行将处于 Running 状态的 Task 切下,任务抢占可以在任何时候发送。

configUSE_TIME_SLICING 表示是否启用时间片轮询,如果启用了时间片轮询,在当前时间片到期的时候即使一个任务处于 Running 状态调度器,调度器也可以将下一个时间片分配给另外一个具有相同优先级且处于Ready 状态的 Task。

2.1 结合抢占优先级与时间片运行的调度(Preemptive With Time Slicing)

采用这种调度算法,如果两个任务的优先级是相同的,他们会进行时间片轮询,如果高优先级的任务来了就会被抢占

Execution pattern highlighting task prioritization and time slicing in a hypothetical application in which two tasks run at the same priority

通过上面这张图可以看到在 t1-t2 这段时间,由于 Task2 与 Idle task 具有相同的优先级,所以他们在不同的时间片切换运行。在 t6 的时候由于 Task1 的优先级较高,所以直接从 Task2 切换为了 Task1.

2.1 仅有抢占优先级但是没有时间片运行的调度(Preemptive Without Time Slicing)

这种算法与前一种算法的唯一区别就是没有时间片轮询了,好处是减少了任务切换所带来的损耗,坏处则是相同优先级的任务所分配的运行时间可能会严重不均。

Execution pattern that demonstrates how tasks of equal priority can receive hugely different amounts of processing time when time slicing is not used

如上面这张图所示,Task2 与 Idle task 具有相同的优先级,但是由于 Idle task 在持续不断的运行,所以 Task2 只能一直处于 Ready 状态无法运行。直到 Task1 由 Running 切换到 Block 状态,调度器重新选择 Task 的时候才选到了 Task2。

2.3 协同调度

Execution pattern demonstrating the behavior of the cooperative scheduler

协同调度是一种非优先级调度,Task 切换仅发生在任务出现 Block 或者使用 taskYIELD 主动让位。

参考

  1. FreeRTOS-Kernel Book Ch04