この質問は主に学術的なものです。これが私にとって実際の問題を引き起こすからではなく、好奇心からお願いします。
次の誤った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
、この場合の値を再チェックする必要があると突然判断するのでしょうか。