OpenMP结果与预期不符

时间:2012-11-01 07:40:39

标签: c++ openmp

我有包含动态3d数组的类。该类的对象调用一个函数进行一些计算以填充1d数组,最后用1d数组数据填充对象的3d数组.1d数组的大小与3d数组相同。
我正在使用Openmp来加强计算。单线程执行给出了正确的结果,但是一旦我转到多个线程,我得到了奇怪的结果。
示例代码如下。请帮助解决问题。

class A (
     void func(float *buf);
     void populateRes(*t); 
      private:
         float ***res;
      };

 A a[n];
 int nthrd = omp_get_num_threads();
 float *buf;
 while (cnt < nz)
 {
      #pragma omp parallel shared(cnt) private(buf, tid, omp_i)
      {
           if(cnt == 0 )
             buf = new float[x*y*z];

           #pragma omp for
           for(omp_i=0; omp_i<n; omp_i++)
           { 
              a[omp_i].func(buf);
              a[omp_i].populateRes(buf);
            }
       }
       cnt++;
       if(cnt >= nz)
          delete []buf;
   }

1 个答案:

答案 0 :(得分:1)

OpenMP不会将不同条目之间的private变量值保存到同一个parallel区域,就像在函数的不同调用之间不保留自动局部变量的值一样(除非它们声明static)。实际上,在大多数OpenMP实现中,parallel区域是单独的函数,private变量是自动的。

这会使您的代码出错,因为buf只会在循环的第一次迭代中分配,但在下一次迭代中,您的代码将在新的未初始化的本地副本上运行。可能会(通过纯粹的机会)发生特定线程的堆栈内容未更改,因此buf保留其值。同样删除buf区域之外的parallel会忽略对new进行多次调用的事实。

如果您只想分配buf一次,则应将while循环放在parallel区域内,反之亦然。这也可以提高性能,因为parallel区域只输入一次,并且每个条目都有相关的开销。

A a[n];

#pragma omp parallel
{
   float *buf = new float[x*y*z];
   for (int cnt = 0; cnt < nz; cnt++)
   {
      #pragma omp for
      for (int i = 0; i < n; i++)
      {
         a[i].func(buf);
         a[i].populateRes(buf);
      }
   }
   delete [] buf;
}

(我没有在内部使用tid所以我冒昧地将其从private变量列表中删除了

更改两个循环的嵌套是可能的,因为for工作共享结构的末尾有一个隐式屏障。我不知道是否有其他代码你已经省略但是给出了问题的代码,cnt循环甚至可以嵌套在工作共享结构中,即:

#pragma omp parallel
{
   float *buf = new float[x*y*z];
   #pragma omp for
   for (int i = 0; i < n; i++)
   {
      for (int cnt = 0; cnt < nz; cnt++)
      {
         a[i].func(buf);
         a[i].populateRes(buf);
      }
   }
   delete [] buf;
}