【问题标题】:Why fails the following OpenMP program to reduce my variable?为什么以下 OpenMP 程序无法减少我的变量?
【发布时间】:2015-10-17 12:05:11
【问题描述】:

考虑以下最小的 C 代码示例。当使用export OMP_NUM_THREADS=4 && gcc -fopenmp minimal.c && ./a.out(Debian 8 上的 GCC 4.9.2)编译和执行时,这会在我的机器上产生五行带有rho=100(有时也是 200 或 400)的行。所有五行打印的预期输出当然是rho=400

如果我在// MARKER 插入更多代码或在此处设置障碍,则程序更有可能产生正确的结果。但即使有另一个障碍,它有时也会失败,我的程序也是如此。所以问题似乎是a在进入reduction循环时没有正确初始化。

OpenMP 4.0.0 manual 甚至在第 55 页上声明 除非指定 nowait 子句,否则在循环结构的末尾有一个隐式障碍。 所以此时应该设置 a .这里出了什么问题?我错过了什么吗?

#include <stdio.h>
#ifdef _OPENMP
#include <omp.h>
#define ID omp_get_thread_num()
#else
#define ID 0
#endif

double a[100];

int main(int argc, char *argv[]) {
    int i;
    double rho;
    #pragma omp parallel
    {
        #pragma omp for
        for (i = 0; i < 100; i++) {
            a[i] = 2;
        }
        // MARKER
        rho = 0.0;
        #pragma omp for reduction(+: rho)
        for (i = 0; i < 100; i++) {
            rho += ((a[i])*(a[i]));
        }
        fprintf(stderr, "[%d] rho=%f\n", ID, rho);
    }
    fprintf(stderr, "[%d] rho=%f\n", ID, rho);
    return 0;
}

【问题讨论】:

  • 修改rho时需要互斥体吗?
  • 我不这么认为。该手册的第 167 页说:reduction 子句指定了一个缩减标识符和一个或多个列表项。对于每个列表项,在每个隐式任务或 SIMD 通道中创建一个私有副本,并使用缩减标识符的初始化器值进行初始化。在区域结束后,使用与缩减标识符关联的组合器将原始列表项更新为私有副本的值。
  • 代码对我来说看起来不错。但是,以防万一,我会在 parallel 指令级别明确声明 private(i)。我知道它应该被私有化,但是......无论如何,这对我来说似乎是一个编译器错误,就像你在omp for 末尾没有隐含的barrier 一样。也许添加一些明确的也可能会有所帮助。
  • 现在我很困惑:我在 GCC 4.9.2 上重现了这个问题,但在 Intel 编译器 16.0.0 上也重现了这个问题(诚然少得多)。我仍然相信代码是正确的,但这动摇了我的信念。

标签: c openmp


【解决方案1】:

好吧,我已经知道答案了,但是我费了很大的劲才得到答案……

这是一个竞争条件,因为rho 是共享的,并且您在并行区域内将其初始化为rho = 0.0;

要么在并行区域之外初始化它,要么在之前使用#pragma omp single 将修复代码...

【讨论】:

  • 我认为您是对的,尽管这很难验证。至少在移动rho = 0.0; 或在该语句之后放置障碍时问题消失了。所以,接受了。第二轮时间:stackoverflow.com/questions/33190809/…
  • 好观察!如果 OP 没有更改她/他的标量代码,而只是使用了 #pragma omp parallel for 两次,则不会发生这种情况。
  • 是的,你是对的。我这样做是因为我认为它更有效,因为程序只需要分支一次。但很可能是错误的,因为线程只创建一次,如果不需要做任何工作,并且由于编译器优化,就会休眠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多