2014-04-18 104 views
2

我做使用OpenMP一些很簡單的測試,在C++中,我遇到一個問題,這可能是愚蠢的,但我無法找出什麼是錯的元素的個數。在下面的MWE:OpenMP的/ C++:在for循環

#include <iostream> 
#include <ctime> 
#include <vector> 
#include <omp.h> 

int main() 
{ 

    int nthreads=1, threadid=0; 
    clock_t tstart, tend; 
    const int nx=10, ny=10, nz=10; 
    int i, j, k; 
    std::vector<std::vector<std::vector<long long int> > > arr_par; 

    arr_par.resize(nx); 
    for (i=0; i<nx; i++) { 
    arr_par[i].resize(ny); 
    for (j = 0; j<ny; j++) { 
     arr_par[i][j].resize(nz); 
    } 
    } 

    tstart = clock(); 
#pragma omp parallel default(shared) private(threadid) 
    { 
#ifdef _OPENMP 
    nthreads = omp_get_num_threads(); 
    threadid = omp_get_thread_num(); 
#endif 
#pragma omp master 
    std::cout<<"OpenMP execution with "<<nthreads<<" threads"<<std::endl; 
#pragma omp end master 
#pragma omp barrier 
#pragma omp critical 
    { 
     std::cout<<"Thread id: "<<threadid<<std::endl; 
    } 

#pragma omp for 
    for (i=0; i<nx; i++) { 
     for (j=0; j<ny; j++) { 
     for (k=0; k<nz; k++) { 
      arr_par[i][j][k] = i*j + k; 
     } 
     } 
    } 
    } 
    tend = clock(); 
    std::cout<<"Elapsed time: "<<(tend - tstart)/double(CLOCKS_PER_SEC)<<" s"<<std::endl; 

    return 0; 
} 

nx如果,nynz等於10,代碼運行平穩。如果我將這些數字增加到20,我會遇到段錯誤。它無論順序運行還是與OMP_NUM_THREADS=1無關,無論有多少個元素。

我使用GCC 4.6.3編譯該死的東西與

g++ -std=c++0x -fopenmp -gstabs+ -O0 test.cpp -o test 

任何想法將不勝感激!

回答

2

你有一個數據的比賽中你的循環計數器:

#pragma omp for 
for (i=0; i<nx; i++) { 
    for (j=0; j<ny; j++) {   // <--- data race 
    for (k=0; k<nz; k++) {  // <--- data race 
     arr_par[i][j][k] = i*j + k; 
    } 
    } 
} 

由於既不j也不k給出private數據共享類,它們的值可能當多個線程試圖增加他們在超過相應的限制一次,導致無法訪問arr_par。的機會,有幾個線程增加jk在與迭代次數的同時增加。

治療的情況下,最好的辦法是簡單地宣佈環路運營商自身內部的循環變量:

#pragma omp for 
for (int i=0; i<nx; i++) { 
    for (int j=0; j<ny; j++) { 
    for (int k=0; k<nz; k++) { 
     arr_par[i][j][k] = i*j + k; 
    } 
    } 
} 

的另一種方法是將private(j,k)條款添加到並行區域的頭:

#pragma omp parallel default(shared) private(threadid) private(j,k) 

由於並行循環的循環變量隱式地變爲私有,因此在您的情況下不要求私有i。不過,如果i用於其他地方的代碼,它可能是有意義的把它變成私有,以防止其他數據爭。

此外,請勿使用clock()來衡量並行應用程序的時間,因爲在大多數Unix操作系統上,它會返回所有線程的總CPU時間。使用omp_get_wtime()代替。