为什么缩减不能用于 OpenMP 任务?

问题描述 投票:0回答:1

这是计算曼德尔布罗特集面积的数值近似值的代码。我不明白为什么在声明并行区域的变量时不能写duction(+ : numoutside) 而不是shared(numoutside) 。当我这样做时,我得到的结果不正确。有人可以解释一下在 OpenMP 任务中使用归约的问题吗,因为它真的让我困惑为什么它不起作用?

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

#define NPOINTS 2000
#define MAXITER 2000

struct complex
{
    double real;
    double imag;
};

int main()
{
    int i, j, iter, numoutside = 0;
    double area, error, ztemp;
    struct complex z, c;

    double time1, time2, elapsed;

    /*
     *
     *
     *     Outer loops run over npoints, initialise z=c
     *
     *     Inner loop has the iteration z=z*z+c, and threshold test
     */

    time1 = omp_get_wtime();

#pragma omp parallel default(none) private(i, j, iter, c, z, ztemp) \
    shared(numoutside) // why not reduction(+ : numoutside) ???
    {
#pragma omp single
        {
            for (i = 0; i < NPOINTS; i++)
            {
#pragma omp task
                for (j = 0; j < NPOINTS; j++)
                {
                    // #pragma omp task - LOSE NE TREBA OVDE - NAPRAVICE SE PREVISE
                    // TASKOVA (NPOINTS * NPOINTS) I USPORICEMO SISTEM UMESTO DA UBRZAMO
                    {
                        c.real = -2.0 + 2.5 * (double)(i) / (double)(NPOINTS) + 1.0e-7;
                        c.imag = 1.125 * (double)(j) / (double)(NPOINTS) + 1.0e-7;
                        z = c;
                        for (iter = 0; iter < MAXITER; iter++)
                        {
                            ztemp = (z.real * z.real) - (z.imag * z.imag) + c.real;
                            z.imag = z.real * z.imag * 2 + c.imag;
                            z.real = ztemp;
                            if ((z.real * z.real + z.imag * z.imag) > 4.0e0)
                            {
#pragma omp atomic
                                numoutside++;
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    time2 = omp_get_wtime();
    elapsed = time2 - time1;
    printf("elapsed %f\n", elapsed);

    /*
     *  Calculate area and error and output the results
     */

    area = 2.0 * 2.5 * 1.125 * (double)(NPOINTS * NPOINTS - numoutside) / (double)(NPOINTS * NPOINTS);
    error = area / (double)NPOINTS;

    printf("Area of Mandlebrot set = %12.8f +/- %12.8f\n", area, error);
}
c parallel-processing multiprocessing openmp
1个回答
0
投票

OpenMP 任务规则有点棘手。默认情况下,封闭 OpenMP 构造中为

shared
的变量在任务中仍为
shared
,否则为
firstprivate

发生了什么:

  • numoutside
    在归约子句中声明,因此编译器为每个线程创建
    numoutside
    的私有实例。
  • single
    指令内,仅使用这些实例之一。
  • 因为
    numoutside
    没有共享,所以它在每个任务中都变成
    firstprivate
    :编译器为每个任务创建一个全新的实例。无论您在任务中的这个实例上做什么,一旦任务结束,它就会丢失。
  • 最后你得到零。

请注意,如果您不使用

numoutside
指令保护
numoutside++
指令,则将
atomic
声明为共享只会偶然起作用。

我不知道如何使用任务结构进行缩减(我已经看到OmpenMP标准中存在一个

task_reduction
子句,但我不知道它是如何工作的)。

但实际上,我想知道为什么你想使用任务而不是简单的并行循环......

© www.soinside.com 2019 - 2024. All rights reserved.