linux - 为什么进程在 Linux 内核中忙于循环时被剥夺 CPU 的时间太长?

标签 linux linux-kernel operating-system kernel kernel-module

乍一看,我的问题可能有点微不足道。请耐心看完。

我在我的 Linux 内核模块中发现了一个繁忙的循环。因此,其他进程(例如 sshd)在很长一段时间内(例如 20 秒)都没有获得 CPU 时间。这是可以理解的,因为我的机器只有一个 CPU,而且繁忙的循环没有机会安排其他进程。

为了实验,我在繁忙的循环中的每次迭代后添加了 schedule() 。尽管这会使 CPU 保持忙碌,但它仍应让其他进程在我调用 schedule() 时运行。但是,这似乎并没有发生。我的用户级进程仍然挂起很长一段时间(20 秒)。

在这种情况下,内核线程获得了 nice 值 -5,用户级线程获得了 nice 值 0。即使用户级线程的优先级较低,我认为 20 秒太长而无法获得 CPU。

有人可以解释为什么会这样吗?

注意:我知道如何完全删除繁忙的循环。但是,我想在这里了解内核的行为。内核版本为2.6.18,内核抢占关闭。

最佳答案

schedule() 函数只是调用调度程序——它没有采取任何特殊措施来安排调用线程将被另一个线程替换。如果当前线程仍然是运行队列中优先级最高的线程,那么调度程序将再次选择它。

听起来好像您的内核线程在其繁忙的循环中只做了很少的工作,而且它每次都在调用 schedule()。因此,它本身可能没有使用太多的 CPU 时间,因此它的优先级也没有降低太多。负 nice 值比正值具有更重的权重,因此 -5 和 0 之间的差异非常明显。这两种影响的结合意味着我对用户空间进程错过并不感到惊讶。

作为实验,您可以尝试在循环的每 N 次迭代中调用调度程序(您必须尝试为您的平台找到合适的 N 值)并查看情况是否更好 - 调用 schedule( ) 过于频繁只会在调度程序中浪费大量 CPU 时间。当然,这只是一个实验 - 正如您已经指出的那样,避免繁忙循环是生产代码中的正确选项,如果您想确保您的线程被另一个线程替换,请将其设置为 TASK_INTERRUPTIBLE 在调用 schedule() 之前将其自身从运行队列中移除(正如评论中已经提到的那样)。

请注意,您的内核 (2.6.18) 正在使用 O(1) 调度程序,该调度程序一直存在到 Completely Fair Scheduler。在 2.6.23 中添加(O(1) 调度程序已在 2.6 中添加以替换更旧的 O(n) scheduler )。 CFS 不使用运行队列并以不同的方式工作,因此您很可能会看到不同的行为——但是我对它不太熟悉,所以我不想准确预测您会看到哪些差异。我已经看够了,知道“完全公平”不是我在具有大量内核和进程的重负载 SMP 系统上使用的术语,但我也承认编写调度程序非常棘手任务,它远非我见过的最糟糕的,而且我在 4-8 核台式机上从未遇到过重大问题。

关于linux - 为什么进程在 Linux 内核中忙于循环时被剥夺 CPU 的时间太长?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13989542/

相关文章:

linux - 操作系统内核是所有其他程序的解释器吗?

c - 为什么是 pause() "efficient use of the CPU"?

python - 为什么在运行时python show file not found 错误?

c++ - 如何在 C++ 中创建一个适用于 Windows 和 Linux 的文件夹(目录)

linux - Vim 语法颜色对某些文件关闭

linux-kernel - 如何在内核/内核配置中禁用 DVFS?

operating-system - 音乐播放器过程

c - execve() 从文件重定向标准输入

Linux 内核 Rootkit 示例

linux - 使用 qemu 和 gdb 调试内核,断点不起作用?