Omp最大减少与存储索引

omp max reduction with storage of index

本文关键字:存储 索引 Omp      更新时间:2023-10-16

使用c++ openmp 3.1,我实现了一个max reduction,它存储了对象向量的整数变量(分数)的最大值。但我也想存储向量索引以访问具有最大分数的对象。我目前不成功的实现是这样的:

//s is a vector of sol objects which contain apart from other variables an  integer     score    variable s[].score            
int bestscore = 0;
int bestant = 0;                
#pragma omp parallel shared(bestant)
{//start parallel session
    #pragma omp for    nowait reduction(max : bestscore)
    for (int ant = 0; ant<maxsols; ++ant) // for all ants
    {
        //procedures on s[ant] object which update the  int s[ant].score
        if (s[ant].score > bestscore)
        {
            //find the object with the highest score
            bestscore = s[ant].score;
            bestant = ant;//i also want know which ant has the highest score
        }
    }
}

代码编译并运行。找到最大bestscore,但bestant得到一个随机索引。连接到最快完成线程的蚂蚁被存储在bestant中。Bestscore以0开始,所以在大多数情况下s[ant]。分数将有更高的分数,最好的分数和最好的是更新。我想我需要一个简化运算符bestant像"on update of bestscore"。

bestant获得随机索引i的原因(如您所怀疑的)是因为bestant是共享的,并且不像bestscore那样从缩减子句中受益。Z玻色子提出的解决方案很好:critical指令块由线程只执行一次,这样开销应该是有限的。

您当时使用的是OpenMP 3.1运行时。我想解释一下,这个限制从OpenMP 4.0开始就已经解决了。现在你可以编写一个用户定义的操作符(参见2.19.5.7 declare reduction Directive)。

在这种情况下,解决方案可以是将这两个值打包到结构体和定义两个这样的struct元素如何在#pragma parallel for循环结束时组合。
//s is a vector of sol objects which contain apart from other variables an  integer     score    variable s[].score
typedef struct {
  int score;
  int ant;
} best_t;
best_t best = { 0, 0 };
// we declare our user reduction operator :
// it is called get_max, return a a value of type best_t.
// omp_out and omp_in are the predefined names of two private elements
// to combine in the end to the final shared variable.
#pragma omp declare reduction(get_max : best_t :
    omp_out = omp_out.score > omp_in.score ? omp_out : omp_in)
    initializer (omp_priv=(omp_orig))
                
#pragma omp parallel 
{//start parallel session
    #pragma omp for    nowait reduction(get_max : best)
    for (int ant = 0; ant<maxsols; ++ant) // for all ants
    {
        //procedures on s[ant] object which update the  int s[ant].score
        if (s[ant].score > best.score)
        {
            //find the object with the highest score
            best.score = s[ant].score;
            best.ant = ant;
        }
    }
}

试试这个

int bestscore = 0;
int bestant = 0;
#pragma omp parallel
{
    int bestscore_private = 0;
    int bestant_private = 0;
    #pragma omp for nowait
    for (int ant = 0; ant<maxsols; ++ant) {         
        if (s[ant].score > bestscore_private) {
            bestscore_private = s[ant].score;
            bestant_private = ant;
        }
    }
    #pragma omp critical 
    {
        if(bestscore_private>bestscore) {
            bestscore = bestscore_private;
            bestant = besant_private;
        }
    }
}

两点观察:

  • 我认为你只需要比较bestscore_privatebestscore时,它的值被改变,这样比较的次数减少。

  • 此外,至少在今天的omp中,您可以在if条件中使用临界区,这样bestscore_privatebestscore之间的比较将并行进行,并且不经常(希望如此)更新到bestscore将以临界方式进行。

    int bestscore = 0;Int bestant = 0;#pragma omp parallel{

      int bestscore_private = 0;
      int bestant_private = 0;
      #pragma omp for nowait
      for (int ant = 0; ant<maxsols; ++ant) {         
          if (s[ant].score > bestscore_private) {
              bestscore_private = s[ant].score;
              bestant_private = ant;   
              if(bestscore_private>bestscore){   
                #pragma omp critical 
                {
                bestscore = bestscore_private;
                bestant = besant_private;
                }
              }
          }
      }
    

    }