我开始学习 OpenMP,但我无法处理这段代码。每次运行都会给出不同的结果。

#include <stdio.h>
#include <omp.h>

int main() {
    int numsmp = 10;
    double d = 0.0;
    double d1 = 0.0;
    float trace[10];
    #pragma omp parallel for num_threads(2) reduction(+ : d, d1)
    for (int i = 0; i < numsmp; i++) {
        for (long int k = 0; k < 2; k++) {
            printf("\n");
            d++;
            printf("i  = %d k = %d d = %lf", i, k, d);
        }
        d1 += d;
        trace[i] = d;
    }
    for (int i = 0; i < 10; i++) {
        printf("\n%lf", trace[i]);
    }
    printf("d1=%f\n", d1);
}

最佳答案

我会注意到,在我的机器上,它似乎给出了一致的(但显然是错误的)结果(60 而不是 110)——但这可能因不同的机器而异,它还可能取决于当前的系统负载。

您的问题是您正在使用减少变量 d 之一来计算另一个。 OpenMP 缩减将为每个线程创建一个局部变量(在这种情况下,每个线程都有一个本地 dd1 )并最终将它们相加。

在您的情况下,如果您不按顺序运行它,您会将 d 的以下值与 d1 相加: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ,但如果您使用 2 个线程(假设他们平均分担负载)运行它,每个线程都会对将其本地 d 的值遵循其本地 d1 : 2, 4, 6, 8, 10 。之后,代码会将每个线程的本地 d1 相加,得出最终结果。

为了检查我们的推理,我们可以自己尝试求和,单线程求和应该给我们 110,代码也是如此。使用 2 个线程应该(假设负载分布均匀)应该给我们 2x30=60,同样,它确实如此。

我将假设这只是一个非常好的最小示例,因此我无法建议您应该如何解决您想要做的任何事情。但在这种情况下,您可以简单地从 d 计算 i 。如果这样的事情是不可能的(在其他一些情况下),您可以使用 critical 区域,但这些并不总是一个好的解决方案(取决于问题)。

可以在这里找到(例如)关于减少的进一步阅读:http://pages.tacc.utexas.edu/~eijkhout/pcse/html/omp-reduction.html

关于c - 带有嵌套 for 循环的 OpenMP 双重缩减,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51080006/

10-13 03:33