本篇目标:讲清抢占——高优先级任务就绪的瞬间,怎么把正在跑的低优先级任务“踢下来”。这是 RTOS 实时性的根基。
一、抢占 vs 非抢占
- 非抢占(合作式):任务自己主动让出(延时、等资源),CPU 才换人。一个任务死循环,全系统陪葬。
- 抢占式:高优先级任务一就绪,立刻打断当前任务。实时性由调度器保证,不依赖任务“自觉”。
stp_rtos 是抢占式的。抢占的触发点有两个:
- tick 中断:延时到期、定时器超时,唤醒更高优先级任务;
- API 调用:
stp_sem_release、stp_thread_resume等让某个高优先级任务就绪。
二、线程状态机
抢占的前提是任务有清晰的状态。stp_rtos 沿用 RT-Thread 的五态模型:
状态 | 含义 | 是否参与调度 |
初始 INIT | 刚创建,还没启动 | 否 |
就绪 READY | 在就绪列表排队 | 是 |
运行 RUNNING | 正在占用 CPU | 当前唯一 |
挂起 SUSPEND | 延时/等资源 | 否 |
关闭 CLOSE | 已结束/删除 | 否 |
状态流转:
stp_thread_init(初始)→ stp_thread_startup(就绪)→ 调度(运行)→ stp_thread_sleep(挂起)→ 定时器超时(就绪)……实现细节:stp_rtos 的
stat 不是简单枚举,而是位标志——STP_THREAD_STAT_MASK 取状态位、STP_THREAD_SUSPEND 等标志可叠加。所以判断状态要用 stat & MASK,不能直接 == 比较。三、抢占是怎么发生的
关键在
stp_schedule 的判断:它不关心“当前线程是不是自愿的”——只要最高优先级就绪线程不是当前线程,就切。低优先级任务被切走时,现场已由 PendSV 完整保存,等下次轮到它再从断点继续,完全无感。
四、为什么切换必须走 PendSV
抢占可能发生在中断里(比如 tick 中断唤醒了高优先级任务)。如果直接在中断里切上下文,会打断正在执行的 ISR,造成中断延迟不可控。所以:
- 中断里只标记需要切换(置 PendSV 挂起位);
- 等所有 ISR 跑完,PendSV(最低优先级)最后执行真正的切换。
这就是原理篇09要展开的“确定性”来源之一。
五、小结
- 抢占 = 调度器发现“最高优先级就绪线程 ≠ 当前线程”就切,不问当前线程意愿;
- 五态模型让“谁能跑、谁在等”一目了然;
- 切换动作统一交给最低优先级的 PendSV,保证中断不被切换拖累。
核心一句话:抢占不是“高优先级抢”,而是“调度器永远选最高的那个”。
- Author:felixfixit
- URL:http://www.felixmicrospace.top/article/priority_preemptive_scheduling_practice
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!







