这个问题主要是学术性的。我是出于好奇而问的,并不是因为这对我构成了实际问题。
考虑以下不正确的 C 程序。
#include <signal.h>
#include <stdio.h>
static int running = 1;
void handler(int u) {
running = 0;
}
int main() {
signal(SIGTERM, handler);
while (running)
;
printf("Bye!\n");
return 0;
}
这个程序是不正确的,因为处理程序中断了程序流程,所以running
可以随时修改,因此应该声明volatile
。但是假设程序员忘记了这一点。
带有标志的 gcc 4.3.3-O3
将循环体(在对running
标志进行一次初始检查后)编译为无限循环
.L7:
jmp .L7
这是意料之中的。
while
现在我们在循环中放入一些微不足道的东西,比如:
while (running)
putchar('.');
突然间,gcc 不再优化循环条件了!循环体的组件现在看起来像这样(再次在 处-O3
):
.L7:
movq stdout(%rip), %rsi
movl $46, %edi
call _IO_putc
movl running(%rip), %eax
testl %eax, %eax
jne .L7
我们看到running
每次循环都会从内存中重新加载;它甚至没有缓存在寄存器中。显然 gcc 现在认为 的值running
可能已经改变。
那么为什么 gcc 突然决定需要重新检查running
这种情况下的值呢?