这是计算曼德尔布罗特集面积的数值近似值的代码。我不明白为什么在声明并行区域的变量时不能写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);
}
OpenMP 任务规则有点棘手。默认情况下,封闭 OpenMP 构造中为
shared
的变量在任务中仍为 shared
,否则为 firstprivate
。
发生了什么:
numoutside
在归约子句中声明,因此编译器为每个线程创建 numoutside
的私有实例。single
指令内,仅使用这些实例之一。numoutside
没有共享,所以它在每个任务中都变成 firstprivate
:编译器为每个任务创建一个全新的实例。无论您在任务中的这个实例上做什么,一旦任务结束,它就会丢失。请注意,如果您不使用
numoutside
指令保护 numoutside++
指令,则将 atomic
声明为共享只会偶然起作用。
我不知道如何使用任务结构进行缩减(我已经看到OmpenMP标准中存在一个
task_reduction
子句,但我不知道它是如何工作的)。
但实际上,我想知道为什么你想使用任务而不是简单的并行循环......