openmp:检查是否嵌套parallesim

Pin*_*oyd 4 c++ openmp

假设我有一个方法乘以两个std::vector:

double multiply(std::vector<double> const& a, std::vector<double> const& b){
    double tmp(0);
    /*here I could easily do a parallelization with*/
    /*#pragma omp parallel loop for*/
    for(unsigned int i=0;i<a.size();i++){
        tmp += a[i]*b[i];
    }
    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

如果我在这个函数中设置了pragma宏,那么调用multiply(...)将在所有线程上运行.

现在假设我还想做其他一些向量乘法:

void many_multiplication(std::vector<double>* a, std::vector<double>* b, unsigned int N){
    /*here I could easily do a parallelization with*/
    /*#pragma omp parallel loop for*/
    for(unsigned int i=0;i<N;i++){
        for(unsigned int j=0;j<N;j++){
            multiply(a[i],b[j]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我也可以用同样的方式进行并行化.但这会导致不必要的嵌套并行性.

如何检查是否multiply(..)在并行区域内调用,然后pragmamultiply(...)"关闭".如果从非平行区域调用它,那么它就会"开启".

Hri*_*iev 5

嵌套并行操作禁用默认情况下,除非通过设置specificially启用OMP_NESTEDtrue或致电omp_set_nested(1);(的§2.3.2 OpenMP规范)明确修改设置筑巢阿维·金斯伯格的建议是一个坏主意.相反,您应该根据嵌套级别使用条件并行执行:

double multiply(std::vector<double> const& a, std::vector<double> const& b){
    double tmp(0);
    int active_levels = omp_get_active_level();
    #pragma omp parallel for reduction(+:tmp) if(active_level < 1)
    for(unsigned int i=0;i<a.size();i++){
        tmp += a[i]+b[i];
    }
    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

omp_get_active_level()返回调用时包含线程的活动并行区域的数量.0如果从并行区域外部或非活动外部区域调用,则返回.由于该if(active_level < 1)子句,并行区域将仅被激活,即并行运行,如果它未包含在活动区域​​中,则无论嵌套设置如何.

如果您的编译器不支持OpenMP 3.0或更高版本(例如,使用任何版本的MS Visual C/C++编译器),则omp_in_parallel()可以使用调用:

double multiply(std::vector<double> const& a, std::vector<double> const& b){
    double tmp(0);
    int in_parallel = omp_in_parallel();
    #pragma omp parallel for reduction(+:tmp) if(in_parallel == 0)
    for(unsigned int i=0;i<a.size();i++){
        tmp += a[i]+b[i];
    }
    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

omp_in_parallel() 如果至少一个封闭的并行区域处于活动状态,则返回非零值,但不提供有关嵌套深度的信息,即灵活性稍差.

无论如何,编写这样的代码是一种不好的做法.您应该简单地保留并行区域,并允许最终用户选择是否应启用嵌套并行.