OpenMP减少,变量不私有?

时间:2018-06-18 14:30:29

标签: c parallel-processing max openmp reduction

我有一个像这样的数组(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初始化为max,因为全局最大值不能小于局部最大值。这样我就可以减少测试次数。

我尝试将其与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)。那为什么会让它崩溃呢?我如何在OpenMP中使用“优化”?

1 个答案:

答案 0 :(得分:2)

首先,用户High Performance Mark在他的评论中是正确的。如果循环索引值取决于计算的值,则不应该使用折叠。在你的例子中,&#34; j&#34;取决于&#34; max&#34;,这将产生不正确的结果。但是,这不是导致分段错误的原因。

我建议您调试您的示例,以便找到崩溃的来源; &#34; MAX&#34;默认情况下正在使用负数进行初始化,这会导致&#34; j&#34;也有说的价值。因此,当尝试访问数组[i * height +( - 2147483648)]时,会出现分段错误。

这是因为OpenMP为每个简化运算符指定了初始值。对于 max运算符,您可以在specification of OpenMP 3.1中找到以下说明:

  

max 缩减列表项目类型

中的最不可表示的值

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

我为你的例子写了一个非常基本的解决方法。我删除了崩溃子句,并且我在并行区域的开头手动初始化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并使用之前的位置。

希望有所帮助