11

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

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

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

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

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

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

4

1 回答 1

2

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

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

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

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

于 2013-02-01T01:34:48.723 回答