FreeRTOS(2)任务状态

除了运行状态之外的状态统称为非运行状态。因为 FreeRTOS 是为单CPU设计的系统,在任何时刻最多只能允许一个任务处在运行状态,哪怕看起来好像有多个任务同时在运行——这只是多个任务不停地切换带来的效果。当一个任务从运行状态切换到非运行状态时,执行时的现场——CPU寄存器被保存在任务的私有堆栈中;在重新回到运行状态时,再从堆栈中恢复之间保存的寄存器。这是任务调度的最基本功能。

img

image-20220408173140183

1.就绪的任务

  ==FreeRTOS 任务的就绪状态表示任务目前没有被执行,但随时可以被执行。当下一次任务切换时机到来时,FreeRTOS 将从就绪任务的列表中选择优先级最高的任务,切换成运行状态。==
  任务优先级是任务的一个属性,FreeRTOS 用整型数表示优先级,最低优先级为0, 最高为 configMAX_PRIORITIES 宏定义的值减去1. 创建任务的时候需要指定一个优先级,在创建之后也可以再通过 vTaskPrioritySet() 函数更改。优先级的意义是,某一个任务处于就绪状态时,只要还存在比它优先级高的任务也处于就绪状态,它就得不到执行的机会。
  当有两个以上相同优先级的任务处于就绪状态时,它们会轮流地得到机会执行,但尽量不要有任务相同优先级(但不保证执行时间是平均分配的),系统不会偏向其中任一个。

2.阻塞的任务

如果一个任务处于等待状态,那么他就为阻塞态。任务进入阻塞态有两种方式

(1)定时事件 vTaskDelay() ,任务在阻塞态延时一段时间,然后退出阻塞态

(2)同步事件—源于其他任务或中断 。比如一个任务一直处于阻塞态直到收到同步事件的信号再退出

任务可以等待同步事件的同时延时一定时间,如果超过该时间没等到信号,则自动退出Blocked

==如果要进行多任务调度,每个任务执行完后必须加个进入阻塞态,不然如果它优先级高,他就会一直执行==

3.挂起的任务

image-20220408174717114

任务切换的时机

  FreeRTOS 在以下情况下必然发生任务切换:
(A) 运行中的任务调用 vTaskSuspend() 将自己挂起。
(B) 运行中的任务调用了vTaskDelay() 延时函数,任务将进入Blocked状态,直至延时结束。在他处于阻塞态时,其他就绪的任务就会执行。
(C) 运行中的任务需要等待一个未发生的同步事件。
  因为是当前任务主动暂停执行,FreeRTOS 需要将它切换到挂起或者阻塞状态,然后从就绪状态的任务列表中选择最高优先级的任务来执行。若已经没有其它需要执行的任务了,还会执行系统自带的,具有最低优先级的 Idle task. 还有一个特殊的情况是
(D) 运行中的任务调用了 taskYIELD() 主动要求切换任务。
  这时候如果就绪任务列表中有同一或更高优先级的任务,将发生任务切换,否则会返回当前任务继续执行。

  如果 FreeRTOS 配置中有 configUSE_PREEMPITON=1, 则进行抢占式任务调度。抢占的意义是在任务就绪列表中新加入的任务(包括新建任务、从挂起状态恢复的任务、从阻塞状态退出的任务),以及被修改了优先级的任务,具有比当前运行任务更高的优先级时,立即切换到那个更高优先级的任务执行。而先前运行的任务不知道自己的执行在何时被暂停,故称为“被抢占”。
  抢占式调度保证了最高优先级的任务一旦运行条件成熟,就会立即得到处理器资源。不过如果最高优先级的任务不止一个时,默认它们是不会相互抢占的,除非再配置了 configUSE_TIME_SLICING=1, 由 FreeRTOS 进行时间片管理。启用时间片管理之后,相同优先级的就绪任务轮流执行,每个任务每次最多执行一个固定的周期,基本上让处理器资源平均分配。  

小结一下,在抢占式调度下任务切换的时机有:
(E) 运行中的任务被更高优先级的任务抢占。
(F) 运行中的任务执行到一个时间片末尾,被同一优先级的任务抢占。

  借用一下手册中的例子。没有抢占式调度的时候是像下图这样:Task3 没有阻塞,需要主动交出控制权才会切换到已经就绪的 Task1, Task2.
img
  而抢占式调度是下面这样:总是立即调度到更高优先级的就绪任务。
img
  启用了时间片轮流调度同优先级任务的抢占式:Task2 和 Idle task都是最低优先级的,轮流执行,在时间片末尾一定切换。
img