【问题标题】:Why processes are deprived of CPU for TOO long while busy looping in Linux kernel?为什么进程在 Linux 内核中忙循环时被剥夺 CPU 时间过长?
【发布时间】:2012-12-08 23:57:52
【问题描述】:

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

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

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

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

有人能解释一下为什么会这样吗?

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

【问题讨论】:

  • 你在进入循环之前设置了状态set_current_state(TASK_INTERRUPTIBLE);吗?
  • 没有。我没有那样做。我希望任务处于 TASK_RUNNING 状态,所以我不需要在外部唤醒它。希望调度程序稍后将其唤醒,因为它已经在运行 Q。
  • 你的内核模块在哪里循环?它是在中断服务例程中还是在您创建的内核线程中?
  • 它在内核线程中,而不是在中断上下文中。
  • 对我来说,您似乎试图放弃 CPU 来执行其他任务,同时仍然持有自旋锁。无论如何,我认为你应该向我们展示你的循环结构(你在哪里持有锁,你在哪里释放它,调度调用在哪里等等)。你的问题对我来说很有趣,我也渴望看到答案!

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


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    相关资源
    最近更新 更多