代码之家  ›  专栏  ›  技术社区  ›  Phantom

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

  •  1
  • Phantom  · 技术社区  · 7 年前

    我有一个这样的数组(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;
        }
      }
    }
    

    对于第二个循环i初始化 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 回复  |  直到 7 年前
        1
  •  2
  •   cppstudy    7 年前

    首先,用户的高性能标记在他的评论中是正确的。如果循环索引值依赖于计算值,则不应使用折叠。在您的示例中,“j”依赖于“max”,这将产生不正确的结果。但是,这并不是造成分割错误的原因。

    我建议您调试您的示例,以便找到崩溃的根源;默认情况下,“max”被初始化为负数,这导致“j”也具有所述值。因此,当试图访问数组[i*Alth+(-2147483648)]时,会得到分割错误。

    这是因为openmp为每个reduction操作符指定了一个初始值。在这种情况下 最大算子 ,您可以在 specification of OpenMP 3.1 :

    最大值 缩减列表项类型中的最小可表示值

    在我们的例子中,这意味着每个线程将在并行区域的开始处拥有最大值的私有副本,该最大变量保存可以作为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的时间并使用前一个位置。

    希望有帮助