Lazy loaded image
原理篇07-Round-Robin,时间片轮转(实践3)
Words 897Read Time 3 min
2026-9-2
🎯
本篇目标:搞清同优先级任务怎么轮流跑。高优先级抢占解决“谁更重要”,时间片轮转解决“同样重要时怎么分”。

一、时间片是什么

时间片(time slice)= 一个任务连续占用 CPU 的最长时间。同优先级的多个就绪任务,每个跑一个时间片,然后换下一个,循环往复——这就是 Round-Robin。
RTOS 里时间片的最小单位是 tick(SysTick 周期)。FreeRTOS 的时间片固定为 1 个 tick(configUSE_TIME_SLICING);RT-Thread 允许配置多个 tick。

二、stp_rtos 的轮转:靠链表插入位置

stp_rtos 模仿 RT-Thread,轮转机制体现在就绪链表的插入位置上。回顾原理篇06的插入逻辑:
  • 任务主动让出(yield)→ 插到链表头部,下次调度优先选中;
  • 任务刚被唤醒/新就绪 → 插到链表尾部,排在同优先级其他任务后面。
配合 stp_schedule 里“总是取链表头”(stp_thread_priority_table[highest].next),同优先级任务自然轮流执行:头部的跑完让出,插回尾部,下一个顶上。
但要分清:这是“协作式轮转”——任务不主动让出(不延时、不阻塞),同优先级的其他任务就轮不到。真正的“时间片抢占”(tick 到期强制切换)stp_rtos 还没有接上,见下一节。

三、remaining_tick:时间片的账本(预留方向)

TCB 里的 remaining_tick 记录剩余时间片。早期实现(stp_tick_increase#if 0 分支)在每次 tick 里扫描所有线程减 remaining_tick,减到 0 就置位优先级组重新参与调度——这就是“tick 到期强制切换”的雏形。思路直观,但每次 tick 都要遍历全部线程,O(n) 开销。
正式实现改成:tick 里只做 ++stp_tickstp_timer_check,不再逐线程扫描,轮转退回“协作式”(靠插入位置)。这是从“轮询”到“事件驱动”的取舍——O(n) 扫描换掉了,但时间片抢占也随之暂缓,留给读者作为扩展练习。

四、空闲任务的礼让

空闲任务优先级最低,但它和“同为最低优先级的用户任务”之间也存在轮转问题:如果空闲任务一直霸占 CPU,同优先级的用户任务就饿死。
FreeRTOS 的做法是 configIDLE_SHOULD_YIELD:空闲任务发现优先级 0 的就绪链表长度 > 1 就 taskYIELD() 主动让出。
stp_rtos 当前的 idle 实现比较朴素,只做计数,没有显式礼让
这意味着:如果用户任务和空闲任务同为最低优先级(STP_THREAD_PRIORITY_MAX-1),且用户任务排在链表后面,它可能得不到运行。这是 stp_rtos 留给读者完善的一个点——可参考 FreeRTOS 的 idle yield 思路补上。

五、小结

  • 时间片轮转只发生在同优先级之间;
  • stp_rtos 当前是“协作式轮转”(靠插入位置),时间片抢占是预留方向;
  • 空闲任务需要礼让,stp_rtos 当前未实现,是明确的完善点。
核心一句话:轮转的本质是“链表取头 + 用完插尾”,但 stp_rtos 目前是协作式,不是抢占式时间片。
上一篇
C++ String 常用操作
下一篇
嵌入式工程师习题集

Comments
Loading...