如何在 OpenMP 中进行有序缩减

How to do an ordered reduction in OpenMP

本文关键字:OpenMP      更新时间:2023-10-16

OpenMP 4.5+ 提供了在C++中执行矢量/数组缩减的功能(新闻稿(

使用上述功能允许我们编写,例如:

#include <vector>
#include <iostream>
int main(){
  std::vector<int> vec;
  #pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))
  #pragma omp parallel for default(none) schedule(static) reduction(merge: vec)
  for(int i=0;i<100;i++)
    vec.push_back(i);
  for(const auto x: vec)
    std::cout<<x<<"n";
  return 0;
}

问题是,在执行此类代码时,各种线程的结果可以以任何方式排序。

有没有办法强制执行顺序,使线程 0 的结果先于线程 1,依此类推?

未明确指定缩减顺序。("OpenMP 程序中合并值的位置以及组合值未指定",OpenMP 4.5 中的 2.15.3.6(。因此,不能使用缩减。

一种方法是按如下方式使用排序:

std::vector<int> vec;
#pragma omp parallel for default(none) schedule(static) shared(vec)
for(int i=0;i<100;i++) {
    // do some computations here
    #pragma omp ordered
    vec.push_back(i);
}

请注意,vec现在是共享的,ordered意味着线程之间执行和同步的序列化。这可能对性能非常不利,除非每次计算都需要大量且统一的时间。

您可以进行自定义顺序缩减。从循环中分离parallel区域for并按顺序手动插入本地结果。

std::vector<int> global_vec;
#pragma omp parallel
{
    std::vector<int> local_vec;
    #pragma omp for schedule(static)
    for (int i=0; i < 100; i++) {
        // some computations
        local_vec.push_back(i);
    }
    for (int t = 0; t < omp_get_num_threads(); t++) {
        #pragma omp barrier
        if (t == omp_get_thread_num()) {
            global_vec.insert(local_vec.begin(), local_vec.end())
        }
    }
}