我不知道循环并行化有什么问题

时间:2018-11-13 14:56:28

标签: c parallel-processing openmp

我不知道为什么,但是此循环的并行化工作不正常:

#pragma omp parallel for private(d) 
for ( i = 0 ; i < nt1 ; i++ ) {
  d = distancia(tabla1[i],tabla2[j]);
  if ( d < dm ) {
    #pragma omp critical
    if ( d < dm ) {
      dm = d;
      im = i;
    }
  }
}
ps[j] = im;

d变量是私有变量,dmim在关键区域内,但是当我执行此代码时(完整代码较大,这只是其中的一小部分)它)输出从顺序版本更改。 谢谢!

2 个答案:

答案 0 :(得分:0)

第一个if ( d < dm ) critical 部分之外,可能是导致争用情况的原因。应该将其删除,因为 critical 部分中已经存在一个。如果您的目的是避免在关键部分过分频繁,那么这不是这样做的方法(请参阅下文)。您可能也必须手动刷新dm(有关#pragma omp flush的一些说明,请参见here)。

distancia函数也可能不是线程安全的(即,依赖于某些不能由多个线程同时编辑的全局变量)。

此外,如果某些距离值相等,则结果不同是正常的。由于没有专门处理这种情况的规则(即采用最小的im),因此将保留遇到的第一个最小值的索引:串行和并行版本中的最小值可能与迭代的顺序不同。

除非distancia函数的计算需要占用大量CPU,否则由于多种原因,您的代码运行速度可能会比串行代码慢。值得注意的是,关键部分的同步开销和变量为dm的缓存共享问题。 最好使用归约方法,其中每个线程计算要执行的任何迭代的最小值,而全局最小值被视为所有线程的最小局部最小值。

float dm=INFINITY;
int im=-1;

#pragma omp parallel shared(dm,im)
{
  // Declare private variables
  float d,dmin_thread,imin_thread;
  dmin_thread=INFINITY;
  imin_thread=-1;

  // loop through i
  #pragma omp for
  for ( i = 0 ; i < nt1 ; i++ ) {
    d = some_function(i);
    // the following lines operate on thread-private variables
    if ( d < dmin_thread) {
      dmin_thread= d;
      imin_thread= i;
      }
    }// end for

  // Reduction part after the loop has been completed
  // The critical section is entered only once by each thread
  #pragma omp critical
  {
    if ( dmin_thread < dm) {
      dm = dmin_thread;
      im = imin_thread;
      }
  }//end critical

}//end parallel

if(im==-1)
  throw_some_error();
else
  do_something_with(im);

答案 1 :(得分:0)

我认为问题在于,即使它是一个关键区域,在顺序版本中,我们也始终会获得最低的i值并添加以下条件:(dm == d && i < im)在条件中我们确保代码仍然以相同的方式工作。我不确定这是否是最好的解决方案,但它非常简单并且对我有用。 这是带有更改的完整代码:

for ( j = 0 ; j < nt2 ; j++ ) {
  dm = MAX_LON + 1;
  #pragma omp parallel for private(d) 
  for ( i = 0 ; i < nt1 ; i++ ) {
    d = distancia(tabla1[i],tabla2[j]);
    if ( d < dm  || (dm == d && i < im)) {
      #pragma omp critical
        {
        if ( d < dm  || (dm == d && i < im)) {
          dm = d;
          im = i;
        }
        }
    }
  }
  ps[j] = im;
}