通过切换上下文实现高效阻塞
避免浪费轮询的一般想法(如在 BSP_delay) 函数中)是将 CPU 上下文从等待线程中切换开,然后在延迟过后切换回上下文。这种等待机制称为阻塞,其主要好处是更有效地使用 CPU,因为被阻塞的线程根本不消耗 CPU 周期。相反,CPU 可以运行其他线程,这些线程实际上有一些有用的事情要做。
从应用程序开发人员的角度来看,行为保持不变 — OS_delay() 函数在请求的延迟过去之前不会返回。但是,OS_delay() 实现会导致内部 RTOS 设计发生剧变。
线程状态
阻塞机制的一个直接后果是,RTOS必须“知道”从调度中排除所有阻塞的线程,这意味着线程需要一个新的状态“阻塞”,以及已经存在的状态“就绪”。
表示对象(如 RTOS 线程)的动态生命周期的一种非常有效的方法是通过状态机。在视频中显示的状态图中,状态被描述为“斑点”,状态变化(称为转换)被描述为“箭头”。这种表示形式的好处是,它迫使你考虑所有可能的状态和转换。例如,对 OS_delay() 的调用会导致转换为“已阻止”状态。但您也可以清楚地看到,需要另一个 RTOS 服务才能从“阻止”状态过渡出来。该服务标识为 OS_tick(),必须从中断(视频中的 SysTick)调用,因为被阻塞的线程无响应且无法执行任何操作。
空闲线程
线程生命周期的状态机表示也会引发以下问题:所有线程是否可以同时处于“阻塞”状态?事实证明他们可以,但是当所有线程都被排除在调度之外时,调度程序应该怎么做?
解决方案是添加一个特殊的空闲线程,当所有其他线程都被阻塞时,CPU 可以切换到该线程。此空闲线程无法阻塞,因此其生命周期没有“阻塞”状态。空闲状态的主要用途是将CPU和外围设备置于低功耗睡眠模式以节省能源(例如,在电池供电的设备中)。事实上,将空闲线程作为执行电源管理的单一集中位置提供是 RTOS 的显著优势之一。