顺序和并行版本给出了不同的结果 - 为什么?

时间:2012-04-07 08:06:13

标签: c++ gcc parallel-processing openmp

我有一个嵌套循环:( L和A是完全定义的输入)

    #pragma omp parallel for schedule(guided) shared(L,A) \
    reduction(+:dummy)
    for (i=k+1;i<row;i++){
            for (n=0;n<k;n++){
                #pragma omp atomic
                dummy += L[i][n]*L[k][n];
                L[i][k] = (A[i][k] - dummy)/L[k][k];
            }
            dummy = 0;
    }

及其顺序版本:

    for (i=k+1;i<row;i++){
            for (n=0;n<k;n++){
                dummy += L[i][n]*L[k][n];
                L[i][k] = (A[i][k] - dummy)/L[k][k];
            }
            dummy = 0;
    }

他们都给出了不同的结果。并行版本比顺序版本要慢得多。

可能导致问题的原因是什么?

编辑:

为了摆脱原子指令引起的问题,我按如下方式修改了代码:

#pragma omp parallel for schedule(guided) shared(L,A) \
    private(i)
    for (i=k+1;i<row;i++){
        double dummyy = 0;
        for (n=0;n<k;n++){
            dummyy += L[i][n]*L[k][n];
            L[i][k] = (A[i][k] - dummyy)/L[k][k];
        }
    }

但它也没有解决问题。结果仍然不同。

3 个答案:

答案 0 :(得分:2)

我对OpenMP不太熟悉,但在我看来,您的计算与订单无关。也就是说,内循环中的结果写入L[i][k],其中ik是内循环的不变量。这意味着在内循环期间相同的值会被覆盖k次,从而导致竞争条件。

此外,dummy似乎在不同的线程之间共享,因此也可能存在竞争条件,除非你的pragma参数以某种方式阻止它。

总之,对我来说,如果你想要顺序执行给出的相同结果,内部循环中的计算必须以相同的顺序执行。因此,只有外环可以并行化。

答案 1 :(得分:2)

在您的并行版本中,您插入了一个不必要的(可能有害的)原子指令。一旦你宣布dummy为减少变量,OpenMP就会停止线程干扰减少。我认为不必要的指令的主要影响是减慢代码的速度。

我看到你有另一个答案来解决你的结果的错误。但我注意到你似乎在每个外循环迭代结束时将dummy设置为0,如果你试图将它用作某种累加器,这似乎很奇怪,这就是减少条款提示。也许你想在内循环中减少到dummy

如果您在减少read this时遇到问题。

答案 2 :(得分:1)

结果的差异来自内部循环变量n,它在线程之间共享,因为它是在omp pragma之外定义的。

澄清: 循环变量n应该在omp pragma中声明,因为它应该是特定于线程的,例如for (int n = 0;.....)