1 任务切换的基础:tick中断(周期性的定时器中断)
FreeRTOS使用定时器产生固定间隔的中断,这叫 Tick、滴答,比如每 10ms 发生一次时钟中断
2 有哪些任务状态?状态切换图
- 阻塞状态(Blocked):等待事件
- 暂停状态(Suspended)
- 就绪状态(Ready)
怎么管理不同状态的任务:放在不同链表里 - 阻塞状态(Blocked)举例:vTaskDelay函数
- 暂停状态(Suspended)举例:vTaskSuspend/vTaskResume
3、vTaskDelay和vTaskDelayUntil
有两个 Delay 函数:
- vTaskDelay:至少等待指定个数的 Tick Interrupt 才能变为就绪状态
- vTaskDelayUntil:等待到指定的绝对时刻,才能变为就绪态,可以使用 xTaskDelayUntil 来让任务周期性地运行
void vTaskDelay( const TickType_t xTicksToDelay ); /* xTicksToDelay: 等待多少给 Tick
*/
/* pxPreviousWakeTime: 上一次被唤醒的时间
* xTimeIncrement: 要阻塞到(pxPreviousWakeTime + xTimeIncrement)
* 单位都是 Tick Count
*/
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,const TickType_t xTimeIncrement );
4、空闲任务及其钩子函数
任务后的清理工作在哪执行?分两类:
- 自杀的任务:在空闲任务中完成清理工作,比如释放内存(都自杀了,怎么清理自己的尸体? 由别人来做)
- 非自杀的任务:在vTaskDelete内部完成清理工作(凶手执行清理工作)
4.1 空闲任务
- 空闲任务优先级为 0:它不能阻碍用户任务运行
- 空闲任务要么处于就绪态, 要么处于运行态,永远不会阻塞
要注意的是:如果使用 vTaskDelete()来删除任务,那么你就要确保空闲任务有机会执行,否则就无法释放被删除任务的内存。
4.2 钩子函数
- 不能导致空闲任务进入阻塞状态、暂停状态
- 如果你会使用 vTaskDelete()来删除任务,那么钩子函数要非常高效地执行。如果空闲任务移植卡在钩子函数里的话,它就无法释放内存
#define configUSE_IDLE_HOOK 1 //把这个宏定义为 1
void vApplicationIdleHook(void)
{
} //实现vApplicationIdleHook函数
5、任务调度算法
5.1 状态与事件
正在运行的任务,被称为"正在使用处理器",它处于运行状态。在单处理器系统中,任何时间里只能有一个任务处于运行状态。
非运行状态的任务,它处于这3种状态之一:
- 阻塞(Blocked)
- 暂停(Suspended)
- 就绪(Ready)
就绪态的任务,可以被调度器挑选出来切换为运行状态,调度器永远都是挑选最高优先级的就绪态任务并让它进入运行状态。
阻塞状态的任务,它在等待"事件",当事件发生时任务就会进入就绪状态。
事件分为两类:
- 时间相关的事件
- 所谓时间相关的事件,就是设置超时时间:在指定时间内阻塞,时间到了就进入就绪状态。
- 使用时间相关的事件,可以实现周期性的功能、可以实现超时功能。
- 同步事件
- 同步事件就是:某个任务在等待某些信息,别的任务或者中断服务程序会给它发送信息。
- 怎么"发送信息"?方法很多
- 任务通知(task notification)
- 队列(queue)
- 事件组(event group)
- 信号量(semaphoe)
- 互斥量(mutex)等
- 这些方法用来发送同步信息,比如表示某个外设得到了数据。
5.2 调度策略
1、是否抢占?高优先级的任务能否优先执行(配置项: configUSE_PREEMPTION)
- 可以:被称作可抢占调度(Pre-emptive),高优先级的就绪任务马上执行,下面再细化。
- 不可以:不能抢就只能协商了,被称作"合作调度模式"(Co-operative Scheduling)
- 当前任务执行时,更高优先级的任务就绪了也不能马上运行,只能等待当前任务主动让出 CPU 资源。
- 其他同优先级的任务也只能等待:更高优先级的任务都不能抢占,平级的更应该老实点
2、允许抢占时,同优先级的任务是否轮流执行?(配置项:configUSE_TIME_SLICING)
- 轮流执行:被称为时间片轮转(Time Slicing),同优先级的任务轮流执行,你执行一个时间片、我再执行一个时间片
- 不轮流执行:英文为"without Time Slicing",当前任务会一直执行,直到主动放弃、或者被高优先级任务抢占
3、允许抢占、允许时间片轮转时,空闲任务是否让步?(配置项: configIDLE_SHOULD_YIELD)
- 空闲任务低人一等,每执行一次循环,就看看是否主动让位给用户任务
- 空闲任务跟用户任务一样,大家轮流执行,没有谁更特殊