OpenMP 减少,变量不是私有的?

OpenMP reduction, variable not private?

我有一个这样的数组(0,0 在左下方):

0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 1 0 1 0 1 0 0
0 0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1

我的目标是获取未完全设置为0的更高行的索引。为此,我编写了以下代码(效果很好):

max=0;
for (i=0 ; i<width ; ++i) {
  for (j=max ; j<height ; ++j) {
    if (array[i*height+j]!=0) {
      max=j;
    }
  }
}

对于第二个循环,我将 j 初始化为最大值,因为全局最大值不能小于局部最大值。这样我就可以减少测试次数。

我尝试将其与 OpenMp 并行化。我的代码现在是:

max=0;
#pragma omp parallel for  default(none)                 \
                          shared(spec, width, height)   \
                          collapse(2)                   \
                          reduction(max:max)
for (i=0 ; i<width ; ++i) {
  for (j=max ; j<height ; ++j) {
    if (array[i*height+j]!=0) {
      max=j;
    }
  }
}

这会导致分段错误。为了让它起作用,我将 j=max 更改为 j=0。所以问题似乎来自 max 变量。

我不明白为什么,因为随着减少,这个变量在每个线程之间应该是私有的(或 lastprivate)。那么为什么它会崩溃呢?我如何将我的 "optimization" 与 OpenMP 一起使用?

首先,High Performance Mark 用户的评论是正确的。如果您的循环索引值取决于计算值,则不应使用 collapse。在您的示例中,"j" 取决于 "max",这将产生不正确的结果。但是,这不是您的分段错误的原因。

我建议你调试你的例子,这样你就可以找到崩溃的根源; "max" 默认用负数初始化,这导致 "j" 也有上述值。因此,当尝试访问数组 [i*height+(-2147483648)] 时,您会遇到分段错误。

发生这种情况是因为 OpenMP 为每个归约运算符指定了一个初始值。对于max运算符,可以在specification of OpenMP 3.1中找到如下描述:

max Least representable value in the reduction list item type

在我们的例子中,这意味着每个线程在并行区域的开始处都有一个 max 变量的私有副本,该副本保存可以存储为 int 的最小数字的值(通常是 -2147483648)。

我已经为您的示例编写了一个非常基本的解决方法。我删除了 collapse 子句,并在并行区域的开头手动初始化 max 变量:

#pragma omp parallel default(none) private(j) shared(array, width, height) reduction(max:max)
{
        // Explicit initialization
        max = 0;

        #pragma omp for 
        for (i=0 ; i<width ; ++i) {
          for (j=max ; j<height ; ++j) {
            if (array[i*height+j]!=0) {
                max=j;
            }
          }
        }
}

额外说明一下,您不需要每次都使用 max=j。您可以尝试检查何时找到第一个 0 并使用之前的位置。

希望对您有所帮助