【问题标题】:#pragma omp flush to make exchange data among threads#pragma omp flush 使线程之间交换数据
【发布时间】:2011-02-24 21:40:04
【问题描述】:

您好,写了一个关于如何使用 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 标志: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    

现在效果很好。谢谢!

【问题讨论】:

  • 小错误....最后输出的第一行开头是:Producer a: 0 flag:1 TID 1

标签: c openmp


【解决方案1】:

不幸的是,使用 flush 比乍看之下要复杂得多。即使是 OpenMP 专家也很难正确使用它。部分问题在于,与列表齐平的定义不正确。基本上它是允许移动的,所以如果你有一个形式的序列:

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

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

无论如何,做你想做的最好的方法是使用flush 没有一个列表,并在你感兴趣的每组变量之后执行flush,并在之前执行flush读取您感兴趣的每个变量。

另一个问题是您没有正确交接。在消费者实际消费所产生的价值之前,您不能在消费者中设置标志以让生产者生成另一个数字。

【讨论】:

  • 感谢您的友好回答....立即尝试从刷新中取出所有列表.....如果我保持部分的顺序,在阅读之前添加一个问题仍然存在... ..
  • 还尝试将 flag=0.... 放在 printf 之后。如果消费者是线程 1,这解决了问题,但如果消费者是线程 0,问题仍然存在(甚至更糟).....再次感谢....
  • 我能够稍微修改您的代码并使其正常工作。由于这通常是一个家庭作业问题,我真的不想只发布代码。仔细看看你与标志的“握手”并完成它。现在问题出在您的代码上。如果您在查看后没有看到它,请发布您的新代码,我会尝试给您进一步的提示。
  • 我有一个有效的代码。但是仍然依赖于部分的顺序。似乎第一部分先于其他部分开始......那是正确的吗?关于“家庭作业”……那堂课我应该是老师。我是一名物理学家,试图向物理专业的学生教授 IT ......也许我会把它作为家庭作业;-)。
  • 很难判断第一部分何时开始。通常它由主线程运行,因此它可以是第一部分启动,也可以在所有其他线程启动后启动。如果你的握手是正确的,那么哪个部分是生产者或消费者都无关紧要,哪个部分先运行也无关紧要。
猜你喜欢
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多