c ++ openmp for循环执行期间的循环最大减少值

时间:2014-10-30 22:56:59

标签: c++ multithreading max openmp reduction

在并行for循环内计算最大减少量时,循环执行期间中间时间内最大减少量变量的值是多少?它是特定线程的最大值还是所有线程的最大值?

我问的原因是我想使用循环内的当前最大值来执行计算,我希望它是所有线程的当前最大值,而不仅仅是执行循环的线程。

例如:

#include <stdio.h>
#include <omp.h>

int main(int argc, char *argv[]) {

    double randomarray[10];
    //initialize the random array

    double outputarray[10];
    double currentmax = 0;

    #pragma omp parallel for reduction(max:currentmax)
    for( i=0;i<10; i++) {

        if(randomarray[i] > currentmax)
        {
            currentmax = randomarray[i];   
        }

        output[i]=randomarray[i]/currentmax;
        // is this current max for the currently 
        // executing thread or all threads?
    }

}

3 个答案:

答案 0 :(得分:2)

在使用reduction关闭的构造中,还原变量的值未定义,并且在线程之间有所不同。每个线程都有变量的私有副本。您将不得不重新考虑并行化。

来自OpenMP 4规范:

  

对于并行和工作共享结构,每个列表的私有副本   创建项目,每个隐式任务一个,就像私有子句一样   已被使用。 ...然后按指定初始化私有副本   以上。在减少条款所在地区的末尾   指定后,原始列表项通过组合其原始更新   使用每个私有副本的最终值的值   指定减少标识符的组合器。

答案 1 :(得分:1)

  

它是仅对特定线程的最大值还是所有线程的最大值?

这是OpenMP并行区域中的“每线程”私有值。

以下代码段可能会实现您想要执行的操作,但它并没有那么有意义。

#pragma omp parallel for
for( i=0;i<10; i++) {
  double local_max;

  #pragma omp critical
  {
    if(randomarray[i] > currentmax)
    {
      currentmax = randomarray[i];   
    }
    local_max = currentmax;
  }

  output[i]=randomarray[i]/local_max;
}

答案 2 :(得分:0)

其他回复清楚地表明openmp max reduction不能提供我需要的功能。所以我找到了另一种通过下面定义的原子最大化操作来实现它的方法:

inline double __sync_fetch_and_max_double(double* address, double val) {
  int64_t* address_as_int64 = (int64_t*)address;
  int64_t old = *address_as_int64, assumed;
  do {
    assumed = old;
    double assumed_double = *((double*)&assumed);
    double min = (val > assumed_double) ? val : assumed_double;
    old = __sync_val_compare_and_swap(address_as_int64, assumed,
                                      *((int64_t*)&min));
  } while (assumed != old);
  return *((double *)&old);
}

然后修改问题中的代码以计算max并存储在所有线程之间共享的单个变量中。由于函数是原子函数,因此变量的值始终具有唯一值,即所有线程的当前最大值。

修改后的代码如下所示:

#include <stdio.h>
#include <omp.h>

int main(int argc, char *argv[]) {

    double randomarray[10];
    //initialize the random array

    double outputarray[10];
    double currentmax = 0;

    #pragma omp parallel for
    for( i=0;i<10; i++) {

        __sync_fetch_and_max_double(&currentmax,randomarray[i]);   

        output[i]=randomarray[i]/currentmax; //max among all threads

    }

}