0

我有包含动态 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;
   }
4

1 回答 1

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;
}
于 2012-11-01T16:25:53.567 回答