时间片调度
← 链表和调度 | ← FreeRTOS内核实现与应用开发实战指南知识地图
调度的几种方式(回顾)
| 调度方式 | 开关 | 说明 |
|---|---|---|
| 优先级抢占调度 | configUSE_PREEMPTION=1(默认) | 高优先级任务就绪立即抢占,正在运行的低优先级任务被踢出 |
| 时间片轮转调度 | configUSE_TIME_SLICING=1(默认) | 同优先级任务轮流执行,每个任务 1 个 tick 时间片(本页主题) |
| 协作式调度 | configUSE_PREEMPTION=0 | 不抢占,只有任务主动让出(阻塞 /taskYIELD())才切换 |
| 事件唤醒调度 | 信号量/队列 API | Give/Send 唤醒等待任务并抢占,见链表和调度 信号任务的调度 |
| 延时到期调度 | SysTick | 阻塞/延时到期任务回就绪链表,见链表和调度 延时任务的调度、空闲任务与阻塞延时 |
时间片轮转:同优先级轮流跑
每个任务默认分到一个 tick 的时间片(tick 周期由 configTICK_RATE_HZ 决定,如 1000Hz → 1ms)。时间片用完(下一次 SysTick 到来)时,若同优先级就绪链表上还有别的任务,就把 CPU 让给下一个,依次轮转:
任务A(优先级3) → 跑1个tick → 任务B(优先级3) → 跑1个tick → 任务A → ...
执行流程(SysTick → PendSV):
- SysTick 中断 →
xTaskIncrementTick():xTickCount加 1,检查当前任务时间片是否用完 - 检查当前优先级链表长度:
> 1说明还有同优先级任务排队 → 标记需要切换,悬起 PendSV vTaskSwitchContext()选任务:taskSELECT_HIGHEST_PRIORITY_TASK()挑最高优先级链表,listGET_OWNER_OF_NEXT_ENTRY()把链表指针挪到下一个节点——这就是轮转的实现- 上下文切换细节见 链表和调度:压栈 CPU 通用寄存器组和特殊寄存器(硬件自动 + 软件手动)、更换
pxCurrentTCB栈顶指针、恢复新任务现场更新 PSP,无感切换
细节:
- 只有自己一个:当前优先级链表长度 = 1,时间片到期也不切换,省掉无谓的上下文切换开销
- 提前阻塞:任务在时间片内主动阻塞(延时/等信号量),它已从就绪链表摘除,自然谈不上轮转
- 高优先级插队:时间片到期时若有更高优先级任务就绪,调度器仍优先切换给高优先级,轮转只发生在同优先级之间