34

我读到 Linux 内核是抢占式的,这与大多数 Unix 内核不同。那么,内核抢占式的真正含义是什么?

一些类比或例子会比纯粹的理论解释更好。

添加 1 -- 2018 年 12 月 7 日上午 11:00

抢先式只是多任务处理的一种范式。还有其他的,例如协作式多任务处理。通过比较它们可以更好地理解。

4

9 回答 9

33

在 Linux 内核版本 2.5.4 之前,Linux 内核不是抢占式的,这意味着在内核模式下运行的进程不能被移出处理器,直到它自己离开处理器或开始等待某些输入输出操作完成。

通常,处于用户态的进程可以通过系统调用进入内核态。以前,当内核是非抢占式的时,较低优先级的进程可以通过重复调用系统调用并保持内核模式来拒绝较高优先级的进程访问处理器,从而优先反转优先级较高的进程。即使较低优先级进程的时间片到期,它也会继续运行,直到它完成内核中的工作或自愿放弃控制。如果等待运行的较高优先级进程是用户正在键入的文本编辑器或准备重新填充其音频缓冲区的 MP3 播放器,则结果是交互性能较差。这种方式非抢占式内核在当时是一个主要缺点。

于 2011-03-12T16:12:03.830 回答
27

想象一下抢先式多任务处理的简单视图。我们有两个用户任务,它们都一直在运行,不使用任何 I/O 或执行内核调用。这两个任务不需要做任何特别的事情就可以在多任务操作系统上运行。内核,通常基于定时器中断,简单地决定是时候让一个任务暂停以让另一个任务运行。有问题的任务完全不知道发生了什么。

但是,大多数任务偶尔会通过系统调用向内核发出请求。发生这种情况时,存在相同的用户上下文,但 CPU 正在代表该任务运行内核代码。

较旧的 Linux 内核永远不会允许在忙于运行内核代码时抢占任务。(请注意,I/O 操作总是自动重新调度。我说的是内核代码有一些 CPU 密集型操作的情况,比如对列表进行排序。)

如果系统允许该任务在运行内核代码时被抢占,那么我们就有了所谓的“抢占内核”。这样的系统不受系统调用期间可能遇到的不可预测延迟的影响,因此它可能更适合嵌入式或实时任务。

例如,如果在特定 CPU 上有两个任务可用,一个需要 5 毫秒才能完成的系统调用,另一个是 MP3 播放器应用程序,需要每 2 毫秒输入一次音频管道,您可能会听到断断续续的音频。

反对抢占的论点是,所有可能在任务上下文中调用的内核代码都必须能够在抢占中幸存下来——例如,有很多糟糕的设备驱动程序代码,如果它总是能够在之前完成一个操作可能会更好允许其他一些任务在该处理器上运行。(现在多处理器系统是规则而不是例外,所有内核代码都必须是可重入的,所以这个论点在今天已经不那么重要了。)此外,如果可以通过使用 bad 改进系统调用来实现相同的目标延迟,也许抢占是不必要的。

一个折衷方案是 CONFIG_PREEMPT_VOLUNTARY,它允许在内核内部的某些点进行任务切换,但不是在任何地方。如果只有少数地方内核代码可能陷入困境,这是一种减少延迟同时保持复杂性可控的廉价方法。

于 2011-03-12T17:18:09.097 回答
10

传统的 unix 内核只有一个锁,在内核代码运行时由一个线程持有。因此,没有其他内核代码可以中断该线程。

这使得设计内核变得更容易,因为您知道当一个线程使用内核资源时,没有其他线程使用。因此不同的线程不能搞乱彼此的工作。

在单处理器系统中,这不会导致太多问题。

但是,在多处理器系统中,您可能会遇到不同处理器或内核上的多个线程都希望同时运行内核代码的情况。这意味着根据工作负载的类型,您可能拥有大量处理器,但它们都将大部分时间都花在了相互等待上。

在 Linux 2.6 中,内核资源被划分为更小的单元,由单独的锁保护,并且审查内核代码以确保仅在相应资源正在使用时才持有锁。所以现在不同的处理器只有在他们想要访问相同的资源(例如硬件资源)时才需要相互等待。

于 2011-03-12T15:54:31.553 回答
5

抢占允许内核给人以并行性的印象:您只有一个处理器(比方说十年前),但您感觉所有进程都在同时运行。那是因为内核抢占(即取消执行)一个进程的执行以将其交给下一个进程(可能根据它们的优先级)。

编辑不是抢占式内核等待进程交还手(即在系统调用期间),因此如果您的进程计算大量数据并且不调用任何类型的yield函数,则其他进程将无法执行执行他们的电话。这样的系统被认为是合作的,因为它们要求流程的合作以确保执行时间的公平性

编辑 2抢占的主要目标是提高系统在多个任务之间的反应性,因此这对最终用户有好处,而另一方面,服务器希望获得最高的吞吐量,所以他们不需要它: (来自Linux内核配置)

于 2011-03-12T15:54:32.103 回答
4

linux 内核是单片的,并为所有正在运行的进程按顺序提供了一点计算时间跨度。这意味着进程(例如程序)不会同时运行,但是会定期给它们一个给定的时间跨度来执行它们的逻辑。主要问题是某些逻辑可能需要更长的时间才能终止并阻止内核为下一个进程留出时间。这会导致系统“滞后”。

抢占式内核具有切换上下文的能力。这意味着它可以停止一个“挂起”的进程,即使它没有完成,并将计算时间按预期交给下一个进程。“挂起”过程将在其时间到来时继续执行而没有任何问题。

实际上,这意味着内核具有实时完成任务的能力,这对于音频录制和编辑特别有趣。

ubuntu studio 发行版包含一个抢占式内核以及大量用于音频和视频编辑的优质免费软件。

于 2011-03-12T15:55:15.803 回答
3

这意味着操作系统调度程序可以自由地暂停正在运行的进程的执行,以便随时将 CPU 交给另一个进程;执行此操作的正常方法是为等待 CPU 的每个进程提供运行 CPU 时间的“量子”。在它过期后,调度程序收回控制权(并且正在运行的进程无法避免这种情况)以将另一个量子分配给另一个进程。

这种方法通常与协作式多任务处理相比较,在协作多任务处理中,进程在需要的所有时间都保持 CPU 不被中断,为了让其他应用程序运行,它们必须显式调用某种“yield”函数;自然地,为了避免给人系统卡住的感觉,表现良好的应用程序会经常让出 CPU。尽管如此,如果应用程序中存在错误(例如,没有yield 调用的无限循环),整个系统将挂起,因为CPU 完全由错误的程序控制。

几乎所有最近的桌面操作系统都使用抢先式多任务处理,即使它在资源方面更昂贵,通常也更稳定(单个故障应用程序更难挂起整个系统,因为操作系统始终处于控制之中)。另一方面,当资源紧张并且期望应用程序表现良好时,使用协作多任务处理。Windows 3 是一种协作式多任务操作系统;最近的一个例子是 RockBox,一个开源 PMP 固件的替代品。

于 2011-03-12T16:05:50.200 回答
2

我认为每个人都很好地解释了这一点,但我只想添加更多信息。在 Linux IRQ、中断和内核调度程序的上下文中。

进程调度程序是操作系统的组件,它负责决定当前正在运行的作业/进程是否应该继续运行,如果不是,那么接下来应该运行哪个进程。

抢占式调度器是一个允许被中断的调度器,一个正在运行的进程可以改变它的状态,然后让另一个进程运行(因为当前进程被中断了)。

另一方面,非抢占式调度器不能从进程(又名合作)中夺走 CPU 仅供参考,“合作”这个词可能会令人困惑,因为这个词的含义并不能清楚地表明调度器实际上做了什么。

例如,像 3.1 这样的旧 Windows 具有协作调度程序。

完全归功于这里的精彩文章

于 2019-03-06T22:07:35.530 回答
0

我认为它从 2.6 开始具有先发制人的作用。抢占式是指当一个新的进程准备好运行时,cpu会被分配给新的进程,它不需要正在运行的进程合作而放弃cpu。

于 2011-03-12T15:53:40.440 回答
0

Linux kernel is preemptive 意味着内核支持抢占。

例如,有两个进程 P1(较高优先级)和 P2(较低优先级)正在执行读取系统调用,并且它们在内核模式下运行。假设 P2 正在运行并且处于内核模式,并且 P2 计划运行。

如果内核抢占可用,那么抢占可以在内核级别发生,即 P2 可以被抢占,但进入睡眠状态,P1 可以继续运行。

如果内核抢占不可用,由于 P2 处于内核模式,系统只需等待 P2 完成,然后

于 2013-08-21T08:47:35.283 回答