用户定义的归约方法每次运行都不会返回预期结果

时间:2019-02-12 13:30:45

标签: c openmp reduction

我正在尝试使用OpenMP并行查找2d数组中的最小值和最大值以及最小值和最大值的索引。在尝试中,我使用了用户定义的减少量,但是每次运行都会得到意想不到的结果。

我尝试检查for循环中的min和max值,似乎在并行化的for循环中,min和max值符合预期。但是,在运行结束时,min和max完全包含wacko值。

我的减少量定义

typedef struct {
    int value;
    int index_i;
    int index_j;
} Point;

#pragma omp declare reduction(minimum : Point : \
    omp_out = omp_in.value < omp_out.value ? omp_in : omp_out) \
    initializer(omp_priv = {INT_MAX, 0, 0})
#pragma omp declare reduction(maximum : Point : \
    omp_out = omp_in.value > omp_out.value ? omp_in : omp_out) \
    initializer(omp_priv = {0, 0, 0})

初始化2d数组,其中size10000

for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
        matrix[i][j] = rand()%99;
    }
}

并行化的循环:

int i, j, total=0;
Point min, max;

#pragma omp parallel for reduction (+:total) reduction(minimum : min) reduction(maximum : max) private(j)
    for (i = 0; i < size; i++) {
        for (j = 0; j < size; j++) {
            total += matrix[i][j];

            if (matrix[i][j] < min.value) {
                min.value = matrix[i][j];
                min.index_i = i;
                min.index_j = j;
            }


            if (matrix[i][j] > max.value) {
                max.value = matrix[i][j];
                max.index_i = i;
                max.index_j = j;
            }
        }
    }

预期结果是索引{{1}处的min = 0和索引(0, 70)处的max = 98

每次的实际结果都不同,但示例输出:

(0, 20)

1 个答案:

答案 0 :(得分:1)

OpenMP的部分思想是,它可以使现有的正确串行代码并行化。一般来说,从正确的OpenMP代码中删除或忽略所有omp编译指示-使其严格按顺序运行-不应更改计算结果。您的代码不满足该要求,因为您没有初始化minmax累积变量。

我猜您希望将简化定义的初始化子句应用于共享变量,但是您对此有误解。初始化子句用于初始化每个线程的本地副本,而不是共享变量。本地副本在某些时候与共享变量结合在一起,作为缩减的一部分,否则,当串行运行时,代码将不会产生相同的结果。

此外,请注意,就C标准而言,OpenMP还原初始化程序子句实际上提供了 initializers 。这些与赋值语句不同,在列表项具有结构类型的情况下,区别尤其明显。您的初始化程序与 初始化程序一样好,但是它们不是有效的赋值表达式。因此,它们不能用于为并行区域内的共享变量分配初始值,因为初始化程序仅作为变量声明的一部分出现。