2015-04-17 137 views
3

考慮下面的代碼:爲什麼GCC優化這個增量?

#include <stdlib.h> 
#include <signal.h> 
#include <stdint.h> 
#include <stdio.h> 

uint64_t counter = 0; 

#define __STDC_FORMAT_MACROS 
#include <inttypes.h> 

void sig_handler(int signo) { 
    printf("%" PRIu64 "\n", counter); 

} 

int main() { 
    struct sigaction act; 
    act.sa_handler = &sig_handler; 
    sigaction(SIGINT, &act, NULL); 

    for(;;) { 
     counter++; 
    } 
    return 0; 
} 

如果我編譯-O0的代碼,我可以看到,櫃檯被當我按CTR + C遞增。與-O1,這是優化了。爲什麼是這樣,我怎麼能避免它?

+5

哎呀,我忘了加'volatile'。 – d33tah

+0

這可能是相關的:http://stackoverflow.com/q/15187459/10077 –

+1

在信號處理程序中,如果它們的類型是'volatile sig_atomic_t'(或者其中一個'std :: atomic' C++ 11中的類型)。 –

回答

4

它看起來像C++草案標準11的下面的部分是相關的部分1.9[intro.execution]

當抽象機的處理是由一個收據 中斷信號,該信號既不是

    類型的易失的std :: sig_atomic_t的
  • 也不
  • 無鎖原子對象的對象的值(29.4)

信號處理程序的執行過程中是未指定的,以及任何 值在任一這兩個類是 由處理器修改的變爲不確定的對象不。

由於counter是陰揮發性也不是原子對象的值是不確定的,因此,編譯器允許優化它經由as-if rule程。

措辭在改變C++ 14草案,我們有以下幾點:

如果信號處理程序作爲對提高函數調用的結果來執行,則處理程序的執行是 在調用raise函數之後和返回之前進行排序。 [注意:由於其他原因收到信號 時,信號處理程序的執行通常與 程序的其餘部分無關。末端注]

這似乎把它留在某種意義上不確定,因爲它僅僅是說,序列處理器是未測序的音符,但如果我們讀N3910: N3910: What can signal handlers do? (CWG 1441)我們可以看到,這似乎被認爲是數據競爭和未定義的行爲。

+0

C++ 14中的措辭已經改變。不幸的是它變得更加複雜,我不能理解它了。 – Brian

+0

@Brian是的,我添加了一篇文章的鏈接,似乎引入了很長的新詞,但基本上它看起來像是數據競賽,即未定義的行爲,但我必須更詳細地閱讀它。 –

1

您的代碼表現出不確定的行爲,根據部分1.10進度保證規則:

實現可以假定任何線索最終將執行下列操作之一:

  • 終止,
  • 打電話給庫I/O功能,
  • 訪問或修改易失性對象,或
  • 執行同步操作或原子操作。

[注意:這是爲了允許編譯器轉換,例如刪除空循環,即使無法證實終止。 - 注意]

因爲你的循環沒有這些,所以優化器可能會假設循環從不輸入,並將其完全刪除。