c - 用户定义的减少每次运行都不会返回预期结果

标签 c openmp reduction

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

我尝试检查 for 循环中的 min 和 max 值,似乎在并行 for 循环内,min 和 max 值符合预期。然而,在运行结束时,最小值和最大值包含完全古怪的值。

我的还原定义

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})

初始化二维数组,其中大小10000

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;
            }
        }
    }

预期结果是索引 (0, 70) 处的 min = 0 和索引 (0) 处的 max = 98 , 20).

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

The min is -290390323 at index (21850, -9176672)
The max is 32595 at index (0, 0)

最佳答案

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

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

此外,请注意,对于 C,OpenMP 缩减初始化子句实际上提供了 C 标准意义上的初始化器。这些与赋值语句不同,在您的情况下,差异尤其明显,其中列表项具有结构类型。您的初始值设定项很好作为初始值设定项,但它们不是有效的赋值表达式。因此,它们不能用于为并行区域内的共享变量分配初始值,因为初始化器仅作为变量声明的一部分出现。

关于c - 用户定义的减少每次运行都不会返回预期结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54651230/

相关文章:

C:多个 fork

c - 一些额外的字符被添加到传递给函数的参数中

c - 在 8 秒内检测 16 GB 笔式驱动器上的内容更改

c++ - 如何使用 openMP 并行化内部循环?

c++ - 使用 OpenMP 并行化 c++ Monte Carlo Integration 的最佳方法是什么?

c++ - OpenMP:同一编译指示上的 nowait 和 reduction 子句

c - 为什么需要 OpenMP 减少子句来使减少并发?

c - 在 Sublime 2(Windows) 中编译 C 程序时出错

algorithm - CUDA:减少或原子操作?

未指定 block 大小的 OpenMP 调度(静态) : chunk size and order of assignment