我写了一个关于如何使用omp flush在线程之间以生产者->消费者的方式交换数据的非常简单的例子,我发现了一个有趣的行为。
int a=-1;
int flag=1;
int count=0;
#pragma omp parallel num_threads(2)
{
int TID;
TID=omp_get_thread_num();
#pragma omp sections
{
#pragma omp section /////////// Producer
{
for(int i=0; i<9;i++)
{
a=i;
#pragma omp flush(a)
flag=1;
printf("Producer a: %d flag:%d TID %d \n",a,flag,TID);
while(flag)
{
#pragma omp flush(flag)
}
}
flag=2;
#pragma omp flush(flag)
} // end producer
#pragma omp section /////////// Consumer
{
while(1) {
count++;
flag=0;
while(!flag)
{
#pragma omp flush(flag)
}
#pragma omp flush(a)
printf("Consumer a: %d Flag: %d count %d TID %d \n",a,flag,count,TID);
if (flag==2) break; // no more data
} // end while(1)
}// end consumer
}// end sections使用以下非常简单的代码将产生错误的输出: Producer a: 0 flag:1 TID 0
生产者a: 1标志:1 TID 0
消费者a: 1标志:1计数1 TID 1
生产者a: 2标志:1 TID 0
消费者a: 2标志:1计数2 TID 1
生产者a: 3标志:1 TID 0
消费者a: 3标志:1计数3 TID 1
生产者a: 4标志:1 TID 0
消费者a: 4标志:1计数4 TID 1
生产者a: 5标志:1 TID 0
消费者a: 5标志:1计数5 TID 1
生产者a: 6标志:1 TID 0
消费者a: 6标志:1计数6 TID 1
生产者a: 7标志:1 TID 0
消费者a: 7标志:1计数7 TID 1
生产者a: 8标志:1 TID 0
消费者a: 8标志:1计数8 TID 1
消费者a: 8标志:2计数9 TID 1
错误在于,消费者忽略了生成的第一个数据a=0。如果我简单地颠倒部分的顺序,让生产者成为线程1,那么一切都是好的……生产者a: 0标志:1 TID 1
消费者a: 0标志:1计数1 TID 0
生产者a: 1标志:1 TID 1
消费者a: 1标志:1计数2 TID 0
……我的错误是什么?
.在与Ejd进行了有趣的讨论之后(谢谢),代码被编辑为:
int a=-1;
int flag=0;
int count=0;
#pragma omp parallel num_threads(2)
{
int TID;
TID=omp_get_thread_num();
#pragma omp sections
{
#pragma omp section /////////// Consumer
{
while(1) {
count++;
if (flag) printf("Consumer a: %d Flag: %d count %d TID %d \n",a,flag,count,TID);
flag=0;
while(!flag)
{
#pragma omp flush(flag)
}
if (flag==2) break; // no more data
} // end while(1)
}// end consumer
#pragma omp section /////////// Producer
{
for(int i=0; i<9;i++)
{
a=i;
printf("Producer a: %d flag:%d TID %d \n",a,flag,TID);
flag=1;
while(flag)
{
#pragma omp flush(flag,a)
}
}
flag=2;
#pragma omp flush(flag)
} // end producer
}// end sections 现在,它运行得很好。谢谢!
发布于 2011-02-25 07:16:47
不幸的是,使用flush要比乍一看复杂得多。即使是OpenMP的专家也很难正确使用它。问题的一部分,是flush with a list定义得不好。基本上它是允许移动的,所以如果你有一个形式的序列:
a = ...
#pragma omp flush(a)
b = ...
#pragma omp flush(b)转储清除( a )必须在a的设置之后,但是可以在设置之后移动并转储清除(B)。的下一次使用之前就必须发生。
在任何情况下,做你想做的事情的最好方法是使用不带列表的flush ,在你感兴趣的每一组变量之后刷新,在读取你感兴趣的每个变量之前做一次刷新。
另一个问题是您没有正确地传递。在消费者实际使用所产生的值之前,您不能在消费者中为生产者设置标志以生成另一个数字。
https://stackoverflow.com/questions/5110816
复制相似问题