为什么以下 OpenMP 程序无法减少我的变量?

Why fails the following OpenMP program to reduce my variable?

考虑以下最小 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 在进入缩减循环时没有正确初始化。

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 是共享的并且您在并行区域内初始化它 rho = 0.0;

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