os/rtos 会安排一个“空闲任务”听起来很合理。那样的话,岂不是很耗电?(空闲任务将执行听起来很合理:while (true) {})
4 回答
这取决于操作系统和 CPU 架构。在 x86(与 Intel 兼容)上,操作系统可能会执行HLT指令,使 CPU 等待直到发生一些有趣的事情,例如硬件中断。据说这会消耗很少的电量。操作系统将执行此操作所花费的时间报告为“空闲”,甚至可能将其分配给虚构的“空闲”进程。
因此,当您在 Windows 任务管理器中看到系统空闲进程正在消耗 90% 的 CPU 时,这实际上意味着 CPU 没有实际的程序来运行 90% 的时间。
这是一篇关于这个主题的好文章:空闲 CPU 做什么?
从历史上看,它有很多不同的方案,尤其是在降低空闲时的功耗成为问题之前。
通常有一个“空闲”进程/任务以最低优先级运行,因此在无事可做时总是得到控制。许多旧系统只会让这个过程运行一个“永远做”循环,而在循环体中没有任何后果。我听说的一个操作系统会在空闲过程中运行机器诊断。许多早期的 PC 会运行内存刷新例程(因为内存需要定期循环,否则会“蒸发”)。
(这个方案的一个好处是 100% 减去空闲进程使用的 % CPU 为您提供了 % CPU 利用率 - 操作系统设计人员赞赏这一功能。)
但是大多数现代系统的标准是运行“暂停”或“等待”指令,或者在进程控制块中设置一个特殊标志,更直接地告诉处理器停止运行并进入省电模式。
总是有代码要运行,如果没有别的,空闲任务就是代码。它可能会执行一条特殊的 CPU 指令来关闭 CPU,直到硬件中断到来。在 x86 CPU 上它是hlt
(停止)。
此答案特定于基于 Windows NT 的操作系统。
空闲线程功能
任务可能因架构而异,但通常这些是空闲线程执行的任务:
- 启用中断以允许传递挂起的中断
- 禁用中断(使用
STI
或CLI
指令,更多关于 wiki) - 在
DEBUG
(或选中的)构建上,查询是否附加了内核调试器并在请求时允许断点 - 处理延迟过程调用
- 检查是否有任何可运行的线程准备好执行。如果有,则使用指向线程的指针更新空闲处理器控制块
- 检查其他处理器的队列,如果可能,调度线程在空闲处理器上等待执行
- 调用电源管理例程,这可能会停止处理器或降低 CPU 滴答率并执行其他类似的节能活动
附加信息
当逻辑处理器没有可运行线程时,Windows 会执行内核模式空闲线程。只有 1 个空闲进程具有与逻辑处理器一样多的空闲线程。因此,在具有 4 个逻辑/物理处理器的四核机器上,将有 1 个空闲进程和 4 个空闲线程。
在 Windows 中,空闲进程的 ID = 0,所有空闲线程也是如此。这些对象由标准EPROCESS/KPROCESS
和ETHREAD/KTHREAD
数据结构表示。但它们不是执行管理器进程和线程对象。没有用户级地址空间,也没有执行用户级代码。
在设置进程管理器和对象管理器之前,空闲进程在系统启动时被静态分配。空闲线程结构在逻辑处理器启动时动态分配。
空闲线程优先级设置为 0。但是,该值实际上并不重要,因为该线程仅在没有其他线程可运行时才被执行。空闲线程优先级永远不会与任何其他线程的优先级进行比较。
空闲线程也是抢占的特例。空闲线程主例程KiIdleLoop
(来自reactos的实现)执行几个不会被其他线程中断的任务。当处理器上没有可运行的线程可用时,该处理器在处理器控制块中被标记为空闲。然后,如果一个可运行线程到达调度执行的队列,则该线程的地址指针被存储在空闲处理器控制块的指针中。在空闲线程运行期间,在循环内的每次迭代中都会检查此指针地址。NextThread
while
资料来源:Windows 内部。M.鲁西诺维奇。第 6 版。第 1 部分,第 453 - 456 页。