【问题标题】:What is a busy loop in C?什么是 C 中的繁忙循环?
【发布时间】:2021-12-20 04:20:26
【问题描述】:

我正在研究如何用 C 编写一个 shell,并且我遇到了一种方法来使用“在实现等待命令时围绕睡眠函数的忙循环”。在循环中,使用了while(1) 循环。我想无条件循环,因此占用一些处理时间和空间?繁忙循环的目的究竟是什么?另外,如果惰性循环中的唯一目标是有一个无条件循环,那么我们就不能使用任何其他形式的循环,例如 for(;;) 而不是 while(1) 吗?

【问题讨论】:

  • 请提供您在问题中提到的文章的链接。
  • 也就是说,在没有仔细查看原始代码的情况下,我会说睡眠功能正在用于将线程放弃给程序中的其他线程。因此,while(1) 将花费很少的处理时间;大部分时间都在睡觉。
  • for(;;)while(1) 完全相同。如果你正在编写一个 shell,你最好将 epollsignalfd 一起使用,而不是任何循环或休眠。
  • 调用 sleep() 而不是阻塞 IO 或完成子进程是错误的,无缘无故地增加了额外的延迟。无论您阅读的任何指南都表明这是垃圾。
  • 我投票结束这个问题,因为它要求对建议的技术提供反馈,但没有提供足够的上下文来理解为什么会建议该技术,而实际上并非如此一种被广泛接受为良好做法的方法。 (Stack Overflow 仅限于“实用的、可回答的”问题;在没有充分理由的情况下使用糟糕的技术不是一个实际的选择。

标签: c linux shell


【解决方案1】:

繁忙的循环是故意浪费时间等待某事发生的循环。通常,您会不惜一切代价避免繁忙的循环,因为它们会消耗 CPU 时间,因此会浪费资源,但在极少数情况下可能需要它们。

其中一种情况确实是当您需要长时间睡眠并且您安装了可能会中断睡眠的信号处理程序之类的东西时。然而,“睡眠繁忙循环”根本算不上是繁忙循环,因为几乎所有时间都花在了睡眠上。

您可以使用您喜欢的任何循环构造来构建繁忙循环,毕竟forwhiledo ... whilegoto 在 C 中都是可互换的构造,只要有适当的控制代码。

这是一个使用clock_nanosleep的例子:

// I want to sleep for 10 seconds, but I cannot do it just with a single
// syscall as it might get interrupted, I need to continue requesting to
// sleep untill the entire 10 seconds have elapsed.

struct timespec requested = { .tv_sec = 10, .tv_nsec = 0 };
struct timespec remaining;
int err;
 
for (;;) {
    err = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested, &remaining);
    
    if (err == 0) {
        // We're done sleeping
        break;
    }

    if (err != EINTR) {
        // Some error occurred, check the value of err
        // Handle err somehow
        break;
    }
        
    // err == EINTR, we did not finish sleeping all the requested time
    // Just keep going...
    requested = remaining;
}

实际的繁忙循环如下所示,其中var 应该是由其他人(例如另一个线程)设置的某种原子变量:

while (var != 1);

// or equivalent

while (1) {
    if (var == 1)
        break;
}

不用说,这是您想要避免的那种循环,因为它会不断检查是否存在浪费 CPU 的条件。更好的实现是使用信号、pthread 条件变量、信号量等。通常有很多不同的方法可以避免忙循环。

最后,请注意,在上述情况下,正如 @einpoklum 在 cmets 中所说,编译器可能会通过放弃对 var 的检查来“优化”整个循环体,除非它知道它可能会改变. volatile 限定符可以提供帮助,但它确实取决于场景,不要把上面的代码当作一个愚蠢的例子。

【讨论】:

  • 请注意,编译器可能会通过删除对var 的检查来“优化”这个循环,除非它知道它可能会改变。
  • @einpoklum 好点,将其添加到答案中。
  • 我不太同意“故意浪费时间”。 可能 是这种情况,但我只真正看到它适用于其明确目的是消耗时间的繁忙循环。当程序员没有做出足够的(或任何)努力来避免浪费时间时,也会出现繁忙的循环,我不认为这是同一件事。
猜你喜欢
  • 1970-01-01
  • 2016-07-29
  • 2017-01-18
  • 2016-11-10
  • 2018-03-09
  • 2021-10-28
  • 2010-11-14
  • 2019-02-19
相关资源
最近更新 更多