问题
Hi writing a very simple example on how to use omp flush to exchange data, in a producer-> consumer way,among threads I have found a funny behavior.
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
Using this very simple code will produce an erroneous output:
Producer a: 0 flag:1 TID 0
Producer a: 1 flag:1 TID 0
Consumer a: 1 Flag: 1 count 1 TID 1
Producer a: 2 flag:1 TID 0
Consumer a: 2 Flag: 1 count 2 TID 1
Producer a: 3 flag:1 TID 0
Consumer a: 3 Flag: 1 count 3 TID 1
Producer a: 4 flag:1 TID 0
Consumer a: 4 Flag: 1 count 4 TID 1
Producer a: 5 flag:1 TID 0
Consumer a: 5 Flag: 1 count 5 TID 1
Producer a: 6 flag:1 TID 0
Consumer a: 6 Flag: 1 count 6 TID 1
Producer a: 7 flag:1 TID 0
Consumer a: 7 Flag: 1 count 7 TID 1
Producer a: 8 flag:1 TID 0
Consumer a: 8 Flag: 1 count 8 TID 1
Consumer a: 8 Flag: 2 count 9 TID 1
The error is that the first datum produced a=0 is ignored by the consumer.
If I simply invert the order of the sections, letting the producer be thread 1 then everything is ok.....
Producer a: 0 flag:1 TID 1
Consumer a: 0 Flag: 1 count 1 TID 0
Producer a: 1 flag:1 TID 1
Consumer a: 1 Flag: 1 count 2 TID 0
....
Whats my mistake ?
..... After the interesting discussion with Ejd (thanks) the code was edited to:
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
That now works nicely. Thanks !
回答1:
Unfortunately using flush is a lot more complicated than it seems at first glance. Even the experts in OpenMP have trouble trying to use it correctly. Part of the problem, is that flush with a list is badly defined. Basically it is allowed to move, so if you have a sequence of the form:
a = ...
#pragma omp flush(a)
b = ...
#pragma omp flush(b)
the flush(a) has to be after the setting of a, but could be moved after the set and flush(b). It just has to occur before the next use of a.
In any case, the best way to do what you want, is to use flush without a list and do the flush after every set of a variable that you are interested in and do a flush before the read of every variable you are interested in.
The other problem is that you are not handing off correctly. You can't set the flag in the consumer for the producer to generate another number until after the consumer has actually consumed the value produced.
来源:https://stackoverflow.com/questions/5110816/pragma-omp-flush-to-make-exchange-data-among-threads