while(1)的目的; 用C语言声明

Purpose of while(1); statement in C

while(1);有什么作用? 我知道while(1)(无分号)无限循环,类似于自旋锁情况。 但是我看不到在哪里可以使用while(1);

样例代码

1
2
3
4
if(!condition)
{
  while(1);
}

注意:这不是do-while()或普通while(1)的情况。


请注意,该语言的所有有效陈述不一定是有目的的。根据该语言的语法,它们是有效的。
可以构建许多类似的"无用"语句,例如if (1);
我将这样的语句看作是条件语句(ifwhile等)与空语句;(虽然显然没有特定目的)也是有效的语句的结合。

话虽如此,我在安全代码中遇到了while (1);。当用户使用嵌入式设备做非常不好的事情时,最好阻止他们尝试其他任何事情。
使用while (1);,我们可以无条件地阻止设备,直到获得授权的操作员手动重启设备为止。

while(1);也可以是内核恐慌的一部分,尽管for(;;) {}循环似乎是表达无限循环的更常用的方式,并且可能存在非空主体(例如panic_blink() )。


如果你深入组装
(从嵌入式系统的角度来看,或者如果您尝试对引导程序进行编程,这将更容易理解)

您将意识到while循环只是一个jmp指令...即

1
2
3
4
5
6
(pseudo code: starting loop address)
add ax, bx
add ax, cx
cmp ax, dx
jz  (pseudo code: another address location)
jmp (pseudo code: starting loop address)

让我们解释一下它是如何工作的,无论如何,处理器将继续按顺序执行指令。因此,当它进入此循环的那一刻,它将在寄存器中添加寄存器bx并存储在ax中,在寄存器中添加寄存器cx并存储到ax,cmp,ax,dx中(这意味着从ax中减去dx),jz指令意味着跳转到(另一个地址如果设置了零标志(如果上述减法的结果为零,则标志寄存器中的一个位将被设置),然后jmp到起始循环地址(非常简单)并重做整个过程。

我打扰您所有这些程序集的原因是为了向您展示这将在C中转换为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int A,B,C,D;
// initialize to what ever;

while(true)
{
A = A + B;
A = A + C;

if((A-D)==0)
{break;}

}

// if((X-Y)==0){break;} is the
// cmp ax, dx
// jz  (pseudo code: another address location)

因此,请想象一下汇编中的senario,如果您有很长的指令列表而不是以jmp(while循环)结尾,可以重复某些部分或加载新程序或执行某些操作...
最终,处理器将到达最后一条指令,然后加载以下指令以查找所有内容(然后将冻结或三重故障等)。

这就是为什么当您希望程序在触发事件之前不执行任何操作时,必须使用while(1)循环,这样处理器才能继续跳转到原来的位置而不会到达该空指令地址。当事件被触发时,它跳转到事件处理程序指令地址,执行它,清除中断,然后返回到while(1)循环,仅跳转到其位置等待进一步的中断。顺便说一句,如果您想了解更多有关while(1)的信息,则称为超循环...对于在这一点上发狂地为之争辩并发表负面评论的人,这不是汇编教程,讲座或任何内容。只是简单的英文解释,就尽可能地简单,它忽略了很多底层的细节,例如指针和堆栈以及诸如此类的东西,并且在某些情况下还简化了事情以使观点更明确。没人在这里寻找文档准确性,我知道这个C代码不会像这样编译,但这仅适用于演示!


这被标记为C,但是我将从C ++的角度开始。在C ++ 11中,编译器可以自由地优化while(1);

从C ++ 11草案标准n3092,第6.5节第5款(强调我的观点):

A loop that, outside of the for-init-statement in the case of a for statement,
— makes no calls to library I/O functions, and
— does not access or modify volatile objects, and
— performs no synchronization operations (1.10) or atomic operations (Clause 29)
may be assumed by the implementation to terminate. [Note: This is intended to allow compiler transformations, such as removal of empty loops, even when termination cannot be proven. — end note ]

C11标准有一个相似的条目,但有一个关键的区别。根据C11草案标准n1570(强调我的):

An iteration statement whose controlling expression is not a constant expression,156) that performs no input/output operations, does not access volatile objects, and performs no synchronization or atomic operations in its body, controlling expression, or (in the case of a for statement) its expression-3, may be assumed by the implementation to terminate.157)
156) An omitted controlling expression is replaced by a nonzero constant, which is a constant expression.
157) This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven.

这意味着while(1);可以假定在C ++ 11中终止,但不能在C11中终止。即使这样,某些供应商仍将注释157(非绑定)解释为允许他们删除该空循环。 C ++ 11和C11中的while(1);之间的区别是已定义行为与未定义行为的区别。由于循环为空,因此可以在C ++ 11中将其删除。在C11中,while(1);被证明是不终止的,这是未定义的行为。由于程序员已调用UB,因此编译器可以自由执行任何操作,包括删除该有害循环。

关于优化删除while(1);的编译器,有许多关于堆栈溢出的讨论。例如,是否允许编译器消除无限循环?,是否可以优化掉用作睡眠的空for循环?,可以优化" while(1);"。在C ++ 0x中。请注意,前两个是C特定的。


嵌入式软件上的一种用法是使用看门狗实现软件重置:

1
while (1);

或同等但更安全,因为它使意图更清晰:

1
do { /* nothing, let's the dog bite */ } while (1);

如果看门狗已启用并且在x毫秒后未得到确认,我们知道它将重置处理器,因此可以使用它来执行软件重置。


我假设while(1);do循环不关联...

我看到的while(1);的唯一半有用的实现是等待中断的空循环。例如父进程正在等待SIGCHLD,表明子进程已终止。在所有子进程终止后,父级的SIGCHLD处理程序可以终止父线程。

它可以解决问题,但会浪费大量CPU时间。这样的用法也许应该执行某种睡眠以定期放弃处理器。


我见过的while(1);的一个地方是嵌入式编程。

该体系结构使用主线程来监视事件,并使用工作线程来处理事件。有一个硬件看门狗定时器(在此说明),将在一段时间后对模块执行软复位。在主线程轮询循环中,它将重置此计时器。如果主线程检测到不可恢复的错误,则将使用while(1);捆绑主线程,从而触发看门狗复位。我相信断言失败也是通过while(1);实现的。


正如其他人所说,这只是一个无所事事的无限循环,完全类似于

1
2
3
while (1) {
    /* Do nothing */
}

分号的循环确实有一个主体。当用作语句时,单个分号是空语句,并且循环主体由该空语句组成。

为了提高可读性,使读者清楚地知道null语句是循环的主体,我建议将其写在单独的一行上:

1
2
while (1)
    ;

否则,很容易在" while"行的末尾漏掉它,因为通常没有分号,读者可能会将下一行误认为是循环的主体。

或者使用空的复合语句。


在AVR芯片组编程(使用C编程语言)中,此语句经常使用,它起着类似于事件循环的作用。

假设我要设计一个递增计数器,因此可以使用以下代码实现它:

1
2
3
4
5
6
7
8
9
10
11
void interrupt0() {
   /* check if key pressed, count up the counter */
}

void main() {
    /* Common inits */
    /* Enable interrupt capability and register its routine */

    /* Event loop */
    while(1);
}

这可用于等待中断。基本上,您初始化所需的所有东西,并开始等待某些事情发生。之后,将调用并执行某些特定功能,然后返回到等待状态。

可以按下按钮,单击鼠标/移动鼠标,接收数据等。

我还要说的是,UI框架实际上经常使用类似的东西。在等待有关用户操作的信号时。


1
while(1);

实际上非常有用。特别是当它是一个具有某种密码的程序,并且您想为用户禁用该程序时,因为例如,他输入了3次错误的密码。使用while(1);会停止程序的运行,直到重新启动程序后,什么都不会发生,主要是出于安全原因。


我认为使用while(1);的原因是因为在代码的较早位置已在此线程上设置了EventHandler或中断。当您知道您的代码只会在很短的时间内"等待"时,使用标准的Thread Safe锁定代码可能会(在时间上)非常昂贵。
因此,您可以使用while(1);设置中断和"旋转",尽管这是一个忙等待(不让CPU空闲/服务其他线程),但设置周期很少。

总而言之,这是线程等待中断或事件时的"廉价"自旋锁。


由于条件始终为真,因此可以说我们正在使用数学中已知的逻辑重言式。
尽管循环证明总是正确的,但除非有代码强制或直到资源崩溃,否则循环不会停止循环。