操作系统调度程序如何重新获得对 CPU 的控制权?
Posted
技术标签:
【中文标题】操作系统调度程序如何重新获得对 CPU 的控制权?【英文标题】:How does the OS scheduler regain control of CPU? 【发布时间】:2012-07-13 11:57:51 【问题描述】:我最近开始学习 CPU 和操作系统是如何工作的,我对使用提供多任务处理的操作系统的单 CPU 机器的操作感到有些困惑。
假设我的机器只有一个 CPU,这意味着在任何给定时间,只能运行一个进程。
现在,我只能假设操作系统用来控制对宝贵CPU时间的访问的调度器也是一个进程。
因此,在这台机器中,用户进程或调度系统进程在任何给定时间点都在运行,但不能同时运行。
所以这里有一个问题:
一旦调度器将 CPU 的控制权让给另一个进程,它如何重新获得 CPU 时间来再次运行自己来完成它的调度工作?我的意思是,如果当前运行的任何给定进程都没有产生 CPU,那么调度程序本身如何再次运行并确保正确的多任务处理?
到目前为止,我一直在想,如果用户进程通过系统调用请求 I/O 操作,那么在系统调用中我们可以确保调度程序再次分配一些 CPU 时间。但我什至不确定这是否能以这种方式工作。
另一方面,如果有问题的用户进程本质上受 CPU 限制,那么从这个角度来看,它可以永远运行,永远不会让其他进程,甚至调度程序再次运行。
假设时间片调度,我不知道调度器如何在另一个进程甚至没有运行的情况下分割时间来执行另一个进程?
非常感谢您在这方面提供的任何见解或参考。
【问题讨论】:
我希望我能足够努力地支持这个问题。我开始学习与您相同的概念并面临相同的问题。在我们的书籍和文章中,这些内容应该与 cpu 和 os 设计的基础知识并列。感谢您发布此信息! 【参考方案1】:操作系统设置了一个硬件计时器(Programmable interval timer 或 PIT),它每 N 毫秒生成一个中断。该中断被传递到内核并且用户代码被中断。
它像任何其他硬件中断一样工作。例如,您的磁盘将在完成 IO 后强制切换到内核。
【讨论】:
这是正确的答案。但例如,在旧系统中为 windows 98 编程时,程序员必须显式调用yield()
命令。否则,没有其他进程可以再次重新获得对 CPU 的控制权,这最终会导致系统崩溃。
如果您首先提到了最重要的 IO 中断,我会再补充一点。
@MatijaSh Windows 98 当然不需要。
为什么win98最终会崩溃?
@MatijaSh,正如 Jalf 所提到的,32 位 Windows(Windows NT 4.0、Windows 95)及其后续版本实现了抢占式多任务处理。您所说的仅与 Windows 3.x 及更早版本(具有协作多任务处理的系统)有关。【参考方案2】:
谷歌“中断”。中断是多线程、抢占式内核(如 Linux/Windows)的核心。没有中断,操作系统永远不会做任何事情。
在调查/学习时,尽量忽略任何在第一段中提到“定时器中断”、“循环”和“时间片”或“量子”的解释——即使不是真的错误,它们也会产生危险的误导.
就操作系统而言,中断有两种形式:
硬件中断 – 由来自外围设备的实际硬件信号启动的中断。这些可以在(几乎)任何时候发生,并将执行从可能正在运行的任何线程切换到驱动程序中的代码。
软件中断 - 由当前运行线程的操作系统调用启动的中断。
任何一个中断都可以请求调度程序使正在等待/运行的线程准备好/运行,或者导致正在等待/运行的线程被抢占。
最重要的中断是来自外围驱动程序的那些硬件中断——那些使线程准备好等待来自磁盘、NIC 卡、鼠标、键盘、USB 等的 IO 的中断。使用的最重要原因抢占式内核,以及锁定、同步、信令等所有问题,是因为此类系统具有非常好的 IO 性能,因为硬件外围设备可以快速使等待来自该硬件的数据的线程准备好/运行, 没有任何延迟,因为线程不产生或等待定期计时器重新调度。
导致周期性调度运行的硬件定时器中断很重要,因为许多系统调用都有超时,以防外设的响应时间超过应有的时间。
在多核系统上,操作系统有一个处理器间驱动程序,可以导致其他内核上的硬件中断,从而允许操作系统将线程中断/调度/分派到多个内核上。
在严重过载的机器上,或那些运行 CPU 密集型应用程序(少数)的机器上,操作系统可以使用周期性定时器中断和由此产生的调度来循环通过一组大于可用内核,并允许每个共享可用 CPU 资源。在大多数系统上,这种情况很少发生,而且并不重要。
每当我看到“量子”、“放弃剩余的时间片”、“循环”等类似内容时,我都会畏缩......
【讨论】:
这是我一直在寻找的正确答案:)【参考方案3】:为了补充@usr的答案,引用Understanding the Linux Kernel:
schedule() 函数
schedule() 实现了调度器。它的目标是找到一个 在运行队列列表中处理,然后将 CPU 分配给它。它是 由几个内核例程直接或以惰性方式调用。 [...]
延迟调用
调度器也可以通过设置 当前[进程]的need_resched字段为1。由于检查了this的值 字段总是在恢复执行用户模式之前生成 过程(参见“从中断和异常返回”一节 第 4 章),schedule() 肯定会在某个接近的时候被调用 未来的时间。
【讨论】:
+1 供参考。我刚刚在您引用的书中找到usr 在其他答案中给出的解释:“当然,单个处理器只能在任何给定时刻运行一个进程。[..] 时间共享依赖于定时器中断,因此是透明的到进程。不需要在程序中插入额外的代码来确保 CPU 时间共享"以上是关于操作系统调度程序如何重新获得对 CPU 的控制权?的主要内容,如果未能解决你的问题,请参考以下文章