2009-06-13 87 views
1

我採取單生產者單消費者隊列,由全球隊列中的一個線程等待另一個線程這樣填寫:GCC優化忙等待的死循環

while (queue.head == queue.tail); 

當我編譯的程序將gcc -O0,它運行良好。但是當它用gcc -O1編譯時,發生了死循環。然後我看着彙編代碼,發現後一版本只檢查了一次(queue.head == queue.tail),如果它不是真的,那麼跳到死循環並且再也不檢查。

我也嘗試將隊列聲明爲volatile,但它不起作用。如何讓gcc意識到隊列在線程間共享並停止優化?非常感謝。

P.S.

1在單線程程序中,可以像這樣優化。但是在我的程序中,queue.tail可以被另一個線程修改。

2我的隊列中聲明如下:

typedef struct { 
    struct my_data data[MAX_QUEUE_LEN]; 
    int head; 
    int tail; 
} my_queue_t; 

volatile my_queue_t queue; 

3我也試着申報頭尾(而不是整個結構)的揮發性,它沒有工作。但是在我宣佈隊列之後,頭部,尾部都變得不穩定,這是有效的。那麼volatile是否應該被聲明爲像這樣的所有相關變量?

+1

你究竟是什麼意思的「死亡發生」? 無論如何,爲什麼*應該*再次檢查?只要它們相等,你的代碼就表示繼續循環。如果不是這樣,它會結束循環,因爲這就是你要求它做的。 – jalf 2009-06-13 18:22:46

+2

您可以顯示隊列的定義......包括您如何嘗試將它們聲明爲volatile。 – 2009-06-13 18:23:26

回答

4

我編譯以下代碼:

struct my_data { 
    int x; 
}; 

typedef struct { 
    struct my_data data[5]; 
    int head; 
    int tail; 
} my_queue_t; 

volatile my_queue_t queue; 

int main() { 
    while (queue.head == queue.tail); 
} 

與:

g++ -S -c -O1 th.cpp 

其中(while循環)中產生的如下因素輸出:

 movl $_queue+20, %edx 
     movl $_queue+24, %eax 
L2: 
     movl (%edx), %ebx 
     movl (%eax), %ecx 
     cmpl %ecx, %ebx 
     je  L2 

其中頭部和尾部在循環內測試加載&。你能發佈你正在發佈的彙編程序嗎?

編輯:使結構聲明中的頭部和尾部不穩定,而不是聲明結構實例易失性,導致相同的代碼。

3

您是否嘗試過將頭/尾聲明爲volatile?