使用C ++中的OpenMP在没有竞争条件的情况下进行打印

时间:2020-05-20 15:47:37

标签: c++ openmp

我正在尝试使用OpenMP来加速我的代码,但是问题是我需要打印内容,而且我不知道如何在没有竞争条件的情况下打印它们。

我的代码看起来像这样:

int some_comp(int n){
  /* some computation */
}

int main(){
  cin >> n;
  #pragma omp parallel for
  for(int i=0; i<=n; i++){
    cout << some_comp(i) << endl;
  }
}

很容易看到(并且很明显)在行中有一个竞争条件可以打印结果,并且每次运行都不同。

我想做的是摆脱比赛条件,以某种方式串行打印所有内容,因为如果我不使用OpenMP,它应该已经打印了。

我考虑过使用某种矢量或列表或其他数据结构,并将所有结果保存在那里,但问题是n <= 2 ^ 64,因此矢量/列表/其他内容将需要太多内存。 / p>

任何想法都会受到赞赏。

1 个答案:

答案 0 :(得分:0)

如果要获得与串行情况相同的输出,这意味着输出中各行的顺序很重要,则可以使用OpenMP的ordered工具:

#pragma omp parallel for schedule(static,1) ordered
for(int i=0; i<=n; i++){
  int result = some_comp(i);
  #pragma omp ordered
  cout << result << endl;
}

这假设some_comp(i)与同步有序执行所花费的时间相比,花费的时间相对较长。您可以详细了解here的工作原理。

如果some_comp(i)的速度与I / O相当或比I / O快,那么将数据存储在缓冲区中并随后依次打印是有意义的:

std::vector<int> results(n);

#pragma omp parallel for
for (int i=0; i<=n; i++){
  results[i] = some_comp(i);
}

for (auto res : results){
  cout << res << endl;
}

如果n很大,而您没有足够的空间来存储巨大的结果向量,则只需将迭代空间划分为多个块:

const int chunk_size = 1000;
std::vector<int> results(chunk_size);

for (int chunk = 0; chunk < (n+1 + chunk_size) / chunk_size; chunk++) {
  const int chunk_start = chunk * chunk_size;
  const int i_max = std::min(n+1 - chunk_start, chunk_size);

  #pragma omp parallel for
  for (int i = 0; i < i_max; i++){
    results[i] = some_comp(chunk_start + i);
  }

  for (int i = 0; i < i_max; i++){
    cout << results[i] << endl;
  }
}

我希望我所有的数学运算都正确,并且在chunk_size除以n+1时也应适用。

还可以将所有代码放在一个并行区域内,以防止多个并行区域的开销,并为顺序部分使用single构造,但是如果您正确选择块大小,执行时间不会有太大差异,并且代码像现在一样更具可读性。