OpenMP / C ++:for循环中的元素数量

时间:2014-04-18 12:02:21

标签: c++ gcc openmp

我正在使用C ++中的OpenMP进行一些非常简单的测试,我遇到的问题可能很愚蠢,但我无法找出错误。在以下MWE中:

#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;
}

如果nxnynz等于10,则代码运行顺畅。如果我将这些数字增加到20,我会得到一个段错误。它可以顺序运行,也可以OMP_NUM_THREADS=1运行,无论元素数量是多少。

我用

编译该死的东西
g++ -std=c++0x -fopenmp -gstabs+ -O0 test.cpp -o test

使用GCC 4.6.3。

任何想法都会受到赞赏!

1 个答案:

答案 0 :(得分: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;
    }
  }
}

由于jk都没有被赋予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()