为什么在Linux内核中繁忙的循环时,为了TOO,进程被剥夺了CPU的权限?

APK*_*Kar 10 linux operating-system kernel kernel-module linux-kernel

乍一看,我的问题可能看起来有点微不足道.请耐心等待,并完整阅读.

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

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

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

有人可以解释为什么会发生这种情况吗?

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

Car*_*roo 2

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

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

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

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