在最早接触嵌入式的时候,我们编写的代码都是在一个while循环里处理所有的事务。
int main()
{
while(1)
{
do_something();
do_something1();
do_something2();
}
}
这三个事务轮流执行。逻辑简单。但会带来一个问题:
事务1在执行的时候,事务2得不到运行,如果此时事务2更紧急,却得不到运行的机会。
因为三个事务轮流执行的。如果事务1和2大部分时间不需要处理,这样就浪费了时间。
所以我们就引入了操作系统的概念。我们把三个事务分成3个task。同时对事务的优先级进行设定。这样紧急的任务可以获得更多的机会运行。
看起来3个任务都同时在运行。但是某一时刻只能有一个任务在运行。任务之间的切换有操作系统的调度器完成。
任务状态
既然任务之间可以切换,同一时刻只能有一个任务在运行。那么任务的状态肯定就会分为很多种。
运行态:
当一个任务正在运行时,那么就说明这个任务处于运行状态,处理运行状态的任务是当前正在使用处理器的任务。如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。
就绪态:
处于就绪态的任务就是那些已经准备就绪(这些任务没有被阻塞或者挂起),可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!
阻塞态:
如果一个任务当前正在等到某个事件的话就会进入阻塞态,比如说如果某个任务调用了vTaskDelay()的话就会进入阻塞态,直到延时周期完成。任务在等待队列、信号量、事件组等的时候就会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使等待的时间还没有到来。
挂起态:
将阻塞一样,任务进入挂起后不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态经过调用函数vTaskSupend()和xTaskResume()。
任务状态转换如下图:
任务优先级
每个任务都可以分配一个从0到configMax_PRIORITIES-1的优先级。数字越低优先级越低。考虑到RAM的消耗,config_PRIORITIMES满足应用即可,不宜设置过大。
调度器确保处于就绪态或者运行态的高优先级任务获得处理器使用权。当configUSE_TIME_SLICING定义为1的时候多个任务可以共用一个优先级。此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。