C语言 为什么这个openMP循环没有返回正确的计算结果?

mi7gmzs6  于 2023-02-11  发布在  其他
关注(0)|答案(1)|浏览(165)

我的代码旨在将两个数组组合成第三个数组,并多次执行此操作。我希望使用OpenMP的方式将其并行化,但结果并不是我所期望的。也就是说,第一个检查已经在a[0]!=0处中断。
MWE是:

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

int main(int argc, char *argv[])
{
    int i = 0;
    int j = 0;
    long length = 10000;
    long nSamples = 1000;
    double *a, *b, *c;
    double start = 0;
    double end = 0;
    int nthreads = 0;

// Array Allocation and Initialisation
    a = (double *)malloc(length * sizeof(double));
    b = (double *)malloc(length * sizeof(double));
    c = (double *)malloc(length * sizeof(double));
    for (i = 0; i < length; i++)
    {
        a[i] = 0.0;
        b[i] = 0.0;
        c[i] = 0.0;
    }

//  Get the maximum number of threads and evaluate the number of threads per group
#pragma omp parallel shared(nthreads)
    {
        nthreads = omp_get_num_threads() / 2;
    }

#pragma omp parallel for shared(nthreads, a, b, c) num_threads(nthreads) collapse(2)
    for (i = 0; i < nSamples; i++)
    {
        for (j = 0; j < length; j++)
        {
            a[j] = a[j] + 2.0;
            b[j] = b[j] + 2.0;
            c[j] = a[j] + b[j];
        }
    }

    /*Check correctness*/
    for (i = 0; i < length; i++)
    {
        if (a[i] != 2.0 * nSamples)
        {
            printf("a not equal at %d\n", i);
            break;
        }
        if (b[i] != 2.0 * nSamples)
        {
            printf("b ot equal at %d\n", i);
            break;
        }
        if (c[i] != 4.0 * nSamples)
        {
            printf("c ot equal at %d\n", i);
            break;
        }
    }

    free(a);
    free(b);
    free(c);
    return 0;
}

如果我只并行化内部循环,检查就能正常工作。为了实现这一点,我用途:

for (i = 0; i < nSamples; i++)
    {
#pragma omp parallel for private(j) shared(a, b, c) num_threads(nthreads)
        for (j = 0; j < length; j++)
        {
            a[j] = a[j] + 2.0;
            b[j] = b[j] + 2.0;
            c[j] = a[j] + b[j];
        }
    }

我知道openMP将循环的每次迭代视为独立于其他迭代。我假设这会导致线程1上的迭代i=5写入另一个线程的迭代i=9的a[j],从而导致差异。这是正确的吗?使用openMP的方法可以避免这种情况吗?

qvtsj1bj

qvtsj1bj1#

因此,问题在于OpenMP将循环的每次迭代视为独立于其他迭代,除非您告诉它减少结果并相应地收集步骤。在上面的示例中,可以通过在外部for循环前面使用以下表达式来实现这一点:

#pragma omp parallel for simd private(i, j) shared(nthreads) num_threads(nthreads) collapse(2) reduction(+               \
                                                                                                         : a[:length], b \
                                                                                                         [:length], c    \
                                                                                                         [:length])

相关问题