c - #pragma omp flush 在线程间交换数据

标签 c openmp

您好,我写了一个非常简单的示例,说明如何使用 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

使用这个非常简单的代码会产生错误的输出: 生产者 a: 0 flag:1 TID 0
生产者 a: 1 flag:1 TID 0
消费者a:1 标志:1 count 1 TID 1
生产者 a: 2 flag:1 TID 0
消费者a:2 标志:1 count 2 TID 1
生产者a: 3 flag:1 TID 0
消费者a:3 标志:1 count 3 TID 1
生产者a: 4 flag:1 TID 0
Consumer a: 4 Flag: 1 count 4 TID 1
生产者 a: 5 flag:1 TID 0
消费者a:5 标志:1 count 5 TID 1
生产者 a: 6 flag:1 TID 0
消费者a:6 标志:1 count 6 TID 1
生产者 a: 7 flag:1 TID 0
消费者a:7 标志:1 count 7 TID 1
生产者 a: 8 flag:1 TID 0
消费者a:8 标志:1 count 8 TID 1
消费者a:8 标志:2 count 9 TID 1

错误是第一个产生的数据 a=0 被消费者忽略了。 如果我简单地颠倒这些部分的顺序,让生产者成为线程 1 那么一切都很好...... 生产者a: 0 flag:1 TID 1
消费者a:0 标志:1 count 1 TID 0
生产者 a: 1 flag:1 TID 1
消费者a:1 标志:1 count 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    

现在效果很好。谢谢!

最佳答案

不幸的是,使用 flush 比乍看起来要复杂得多。即使是 OpenMP 专家也难以正确使用它。问题的一部分是 flush with a list 定义错误。基本上它是允许移动的,所以如果你有一个形式的序列:

a = ...
#pragma omp flush(a)
b = ...
#pragma omp flush(b)

flush(a) 必须在 a 的设置之后,但可以在 set 和 flush(b) 之后移动。它只需要在下一次使用 a 之前发生。

在任何情况下,做你想做的最好的方法是使用 flush without 列表并在你感兴趣的每组变量之后进行冲洗并在之前进行冲洗读取您感兴趣的每个变量。

另一个问题是你没有正确地交接。您不能在消费者中设置标志,让生产者生成另一个数字,直到消费者实际消费了所产生的值(value)。

关于c - #pragma omp flush 在线程间交换数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5110816/

相关文章:

c++ - 如何在c/c++中输入实时数据进行实时处理

c - 使用 uint8_t 数组进行 fwrite

c - 在字符串操作中获取段错误

c - 了解某些 ELF 文件结构

c++ - 如何正确使用 OpenMP 中的 update() 子句

r - 在 CRAN 上传递 R 包,并在 MACOS 上有问题 + OpenMP

c - 将复合文字分配给数组指针会在同一地点和时间同时给出预期结果和垃圾?

c++ - 使用 openmp 进行 LU 分解

python - 使用 OpenMp 与 ctypes 进行链接

c++ - OpenMP 代码大部分时间都在等待 Join Barrier