Этот вопрос в основном академический. Я прошу из любопытства не потому, что это создает для меня настоящую проблему.
Рассмотрим следующую неправильную программу 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
?