1、任务调度简介
调度器就是使用相关的调度算法来决定当前需要执行哪个任务,也可以理解为调度器就是调度算法,就比如果我们在simulink模型中写一个控制算法,就会给它起一个控制器的名字,说白了控制器就是一个算法。
FreeRTOS一共支持三种任务调度方式:
抢占式调度:主要是针对优先级不同的任务,每个任务都有一个优先级,优先级高的任务可以抢占优先级低的任务。其实吧,这东西跟中断差不多,中断其实也是抢占式的。
时间片调度:主要是针对优先级相同的任务,当多个任务的优先级相同时,任务调度器会在每一次系统时钟节拍到的时候切换任务。
其实抢占式调度和时间片调度便是实时性得以实现的原因了,当任务优先级一样时,每个任务执行一个时间片(1ms)的时间,当任务优先级不同时,高优先级任务抢占低优先级任务,当高优先级任务进入阻塞态(延迟)或者挂起态时,低优先级任务可以执行。只要时间够快,你就会认为他是实时性的。
协程式调度:当前执行任务将会一直运行,同时高优先级的任务不会抢占低优先级的任务。FreeRTOS虽然现在还支持,但是官方已经表示不再更新协程式调度了。感觉这个调度,咋看咋觉得它和实时性背道而驰呢。
2、任务状态
FreeRTOS中任务共存在4中状态:
运行态:顾名思义,正在执行的任务,该任务就处于运行态,此时该任务占用处理器。
就绪态:顾名思义,如果任务已经能够执行了,但当前还未被执行,那么该任务就处于就绪态。新创建的任务会初始化为就绪态。
阻塞态:如果一任务因延时或等待外部事件发生而处于没有实际动作的状态,那么这个任务就处于阻塞态。包含任务被挂起、任务被延时、任务正在等待信号量、读写队列或者等待读写事件等。
挂起态:类似暂停,调用函数vTaskSuspend()进入挂起态,需要调用解卦函数vTaskResume()才可以进入就绪态。处于挂起态的任务对调度器而言是不可见的。
阻塞态和挂起态肯定不一样,我现在的理解是阻塞态是在任务运行中出现vDelay()延时函数或者等待其他外部事件时进入的状态,进入阻塞态后,其他处于就绪态的低优先级任务可以执行,当延时结束或者外部事件发生时,低优先级任务被打断,继续执行该任务。
挂起态是不再执行了,知道解挂,而阻塞态是任务依然在执行,只是在等待某些条件才能继续执行。
而挂起态则是由API函数实现,任务自身可不可以挂起自己?可不可以解挂自己?或者是由中断挂起任务解挂任务?
四种状态之间的转换图:
总结:
第一,先说运行态,运行态可以通过调用API函数编程挂起态、就绪态、阻塞态,但是运行态只能由就绪态转变而来。
第二,说就绪态,就绪态是唯一一个可以变成运行态的状态,任务被创建好后直接进入就绪态,就绪态可以变成挂起态,也可以由挂起态变回来,但是只能由阻塞态单向转换。
第三,挂起态,任何状态都可以变成挂起态, 挂起态只能变成就绪态。
第四,阻塞态,阻塞态只能由运行态转换过来。
任务状态列表:
在前面所说的四种状态中,除了运行态,其他三种任务状态的任务都有其对应的任务状态列表,解释一手,任务状态列表里边存放处于该状态的任务,比如,task1、2、3分别处于就绪态、阻塞态、挂起态,那么!task1、2、3就分别放在就绪、阻塞、挂起列表里边。
就绪列表:pxReadyTasksLists[x],其中x代表任务优先级数值。
其实这便是前一篇文章FreeRTOS入门-CSDN博客所讲的执行最高优先级的任务的算法使用硬件方法,32位变量,当某个位置一时,代表所对应的优先级就序列表有任务存在,至于软件方法,我觉得得阅读FreeRTOS代码才可以理解,我现在还不会.....
注意:
1、调度器总是在所有处于就绪列表的任务中,选择具有最高优先级的任务来执行,抢占式嘛。
2、相同优先级的任务会连接在同一个就绪列表上,时间片调度嘛。