2012-04-24 51 views
7

我找了一些代碼審查和所遇到忙等待這樣:用作睡眠的空循環會被優化掉嗎?

int loop = us*32; 
int x; 
for(x = 0;x<loop;x++) 
{ 
    /*do nothing*/  
} 

我似乎記得讀這些空循環可以被優化掉。這是會發生在這裏還是可以工作?

+1

http://stackoverflow.com/questions/3527829/is-this -a-bug-in-the-intel -c-compiler-icc/3527862#3527862 – 2012-04-24 14:42:37

+1

yes ............ – 2012-04-24 14:42:40

+0

'us'?如果這個代碼工作,必須是一個非常慢的CPU。 – 2012-04-24 14:45:15

回答

12

你處於編譯器的擺佈之中。事實上,如果它很聰明,它會檢測到它是一個noop。順便說一句,尼爾·巴特沃斯有一個nice post,他在這裏也涉及到這個問題。

+3

如果您啓用優化。 – Kevin 2012-04-24 14:43:36

+0

感謝您的回答。這是我腦海中的事情,說這種事情可能是一個問題 – Firedragon 2012-04-24 14:46:02

+0

不是真的,即使你不能發出內聯彙編代碼,編譯器也不會(也不能)用本地side-效果。 – 2012-04-26 08:34:51

2

一些編譯器,比如gcc,會檢測到它是一個空循環,特別是對於這個循環來說很悲觀,期望你把它放在那裏作爲一個延遲循環。你可以閱讀更多關於http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Non_002dbugs.html

請注意,這是編譯器特定的,

+1

的確,我用mingw/msvc來解決這個問題,在那裏我不得不調試代碼,以便對另一個線程修改的變量進行繁忙的等待,並且循環被「優化」(在mingw情況下只用-O2)一個跳轉到自身的jmp語句(即無限循環),調試起來非常有趣。 :) – aphax 2012-10-30 22:23:24

4

這是非常不便攜的東西。

在一些編譯器這些可能的作品之一(但你必須檢查啓用了全面優化,空指令可以被扔掉):

for (i = 0; i < spinCount;) 
    ++i; // yes, HERE 

或:

for (i = 0; i < spinCount; ++i) 
    ((void)0);  

如果您幸運的是,你的編譯器可能會提供一個宏或者一個內部函數,這些函數將被編譯成nop彙編指令,類似於MSVC中的__noop

截至上的資源,你可以簡單地添加一個單一的彙編指令(這是編譯器相關的,也可能是__asm或類似的東西)來執行...什麼都沒有,這樣的:

for (i = 0; i < spinCount; ++i) 
    __asm nop 

或(檢查編譯器文檔):

for (i = 0; i < spinCount; ++i) 
    asm("nop"); 

編輯
如果沒有noop指令,你可以不加彙編代碼(對不起,什麼樣的COM )你可以依賴於這樣的假設,即帶有副作用的指令不會被優化掉(或者,如由@ouah發佈的,訪問被聲明爲volatile的變量)。

13

答案是肯定的,編譯器可以優化循環。

使用volatile預選賽避免優化:

int loop = us * 32; 
volatile int x; 
for (x = 0; x < loop; x++) 
{ 
    /*do nothing*/  
} 

如果您在嵌入式編程世界閱讀你的編譯器的文檔,因爲他們通常提供延時函數等待一定的循環或微秒傳入參數。

例如,avr-gccutil/delay.h以下功能:在語言標準

void _delay_us(double __us); 
+0

非常有用的評論。謝謝 – Firedragon 2012-04-25 08:45:05

+0

閱讀關於爲什麼要使用volatile關鍵字的美麗教程:http://www.embedded.com/electronics-blogs/beginner-s-corner/4023801/Introduction-to-the-Volatile-Keyword – Prabhpreet 2014-06-16 13:57:35

2

沒有禁止,所以編譯器可以做到這一點,如果他們能夠。

讓我們編譯GCC 4.8,看看它做什麼

輸入代碼:

int main() { 
    int i; 
    for(i = 0; i < 16; i++) 
     ; 
} 

編譯和反編譯:

gcc -c -g -std=c99 -O0 a.c 
objudmp -S a.o 

輸出:

a.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <main>: 
int main() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    int i; 
    for(i = 0; i < 16; i++) 
    4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 
    b: eb 04     jmp 11 <main+0x11> 
    d: 83 45 fc 01    addl $0x1,-0x4(%rbp) 
    11: 83 7d fc 0f    cmpl $0xf,-0x4(%rbp) 
    15: 7e f6     jle d <main+0xd> 
    17: b8 00 00 00 00   mov $0x0,%eax 
     ; 
} 
    1c: 5d      pop %rbp 
    1d: c3      retq 

循環在那裏:jle跳回。

隨着-O3

0000000000000000 <main>: 
    0: 31 c0     xor %eax,%eax 
    2: c3      retq 

剛剛返回0,所以它完全優化掉。

對於任何編譯器都可以進行相同的分析。