2012-11-01 185 views
0

我有包含動態3D數組的類。該類的對象調用一個函數,該函數執行一些計算來填充1d數組,並在最後用1d數組數據填充對象的3d數組.1d數組的大小與3d數組的大小相同。
我正在使用Openmp來加速計算。單線程執行正在給出正確的結果,但是一旦我進入多線程,我就會得到奇怪的結果。
示例代碼如下。請幫助解決問題。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

OpenMP的不保留不同的條目之間private變量的值到同parallel區域,未保留的功能的不同調用之間的自動局部變量的值的方法相同(除非它們聲明static) 。實際上,在大多數OpenMP實現中,parallel區域是單獨的函數,private變量是自動的。

這使得您的代碼錯誤,因爲buf只會在循環的第一次迭代中分配,但隨後在接下來的迭代您的代碼將在一個新的未初始化本地副本運行。它可能發生(純粹的機會)特定線程的堆棧內容不會改變,因此保留其價值。在parallel區域之外還刪除buf忽略了有多個呼叫到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; 
}