2009-06-13 52 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?