为什么在Linux内核中循环繁忙的时候,进程被剥夺了太长的CPU?

乍一看,我的问题可能看起来有点微不足道。 请忍耐,完全阅读。

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

为了实验,我在忙循环中每次迭代之后都添加了schedule()。 尽pipe如此,这将使CPU保持忙碌状态,但应该让其他进程运行,因为我正在调用schedule()。 但是,这似乎并没有发生。 我的用户级别进程仍然持续很长时间(20秒)。

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

有人可以解释为什么这可能发生?

注意:我知道如何彻底删除忙碌循环。 但是,我想在这里理解内核的行为。 内核版本是2.6.18,内核抢占被禁用。

Solutions Collecting From Web of "为什么在Linux内核中循环繁忙的时候,进程被剥夺了太长的CPU?"

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

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

作为一个实验,你可以在循环的第N次迭代中尝试调用调度器(你必须尝试为你的平台找到一个好的N值),看看情况是否更好 – 调用schedule()往往会浪费调度程序中有很多CPU时间。 当然,这只是一个实验 – 正如您已经指出的那样,避免繁忙循环是生产代码中的正确选项,如果您想确保您的线程被另一个线程替换,则在调用schedule()之前将其设置为TASK_INTERRUPTIBLE schedule()远离运行队列(如已经在注释中提到的那样)。

请注意,你的内核(2.6.18)正在使用O(1)调度器,该调度器一直存在,直到2.6.23中添加完全公平调度器 (在2.6中添加了O(1)调度器以替换更旧的O(n )调度程序 )。 CFS不会使用跑步队列,而是以不同的方式工作,所以你可能会看到不同的行为 – 但是我不太了解它,所以我不想预测你会看到什么差异。 我已经看到了足够的知道,“完全公平”并不是我用在重负载的SMP系统上,并且有大量的内核和进程,但是我也接受编写一个调度器是非常棘手的任务,这远远不是我所见过的最糟糕的事情,而我在4-8核心桌面机器上从来没有遇到过很大的问题。