在C++11中使用OpenMP找到计算值的最大值

问题描述 投票:0回答:3

我正在寻找 for 循环内计算值的最大值,并存储其相应的索引,max_calc_valuei_max在这里,下面是我的伪代码。我想知道是否可以在这里进行某种减少:

double max_calc_value = -DBL_MAX; // minimum double value
#pragma omp parallel for
for (int i = 20; i < 1000; i++) {
    this_value = my_slow_function(large_double_vector_array, param1*i, .., param5+i);
    if (this_value > max_calc_value){
        max_calc_value = this_value;
        i_max = i;
    }
}
c++ c++11 openmp
3个回答
7
投票

如果您愿意,您可以定义自定义归约函数并并行使用它。在您的具体示例中,这可能会使代码比简单地使用

critical
部分更加麻烦。然而,如果您的实际代码可以从使用此自定义缩减函数中全局受益,这可能会很好地适用,不仅对于最终的并行缩减,而且对于本地代码...... 因此,如果它适用于您,这里有一个关于它如何工作的示例:

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

struct dbl_int {
    double val;
    int idx;
};

const dbl_int& max( const dbl_int& a, const dbl_int& b) {
    return a.val > b.val ? a : b;
}

#pragma omp declare reduction( maxVal: dbl_int: omp_out=max( omp_out, omp_in ) )

int main() {
    dbl_int di = { -100., -1 };
    #pragma omp parallel num_threads( 10 ) reduction( maxVal: di )
    {
        di.val = omp_get_thread_num() % 7;
        di.idx = omp_get_thread_num();
    }
    std::cout << "Upon exit, value=" << di.val << " and index=" << di.idx << std::endl;
    return 0;
}

这给了我:

~/tmp $ g++ -fopenmp myred.cc -o myred
~/tmp $ ./myred
Upon exit, value=6 and index=6

4
投票

处理它的最佳方法是定义自定义归约操作,如 Gilles 的答案所示。如果您的编译器仅支持 OpenMP 3.1 或更早版本(OpenMP 4.0 中引入了自定义归约操作),那么正确的解决方案是在每个线程中执行局部归约,然后按顺序组合局部归约:

double max_calc_value = -DBL_MAX; // minimum double value
int i_max = -1;
#pragma omp parallel
{
    int my_i_max = -1;
    double my_value = -DBL_MAX;

    #pragma omp for
    for (int i = 20; i < 1000; i++) {
        this_value = my_slow_function(large_double_vector_array, param1*i, .., param5+i);
        if (this_value > my_value){
            my_value = this_value;
            my_i_max = i;
        }
    }

    #pragma omp critical
    {
        if (my_value > max_calc_value) {
            max_calc_value = my_value;
            i_max = my_i_max;
        }
    }
}

这最大限度地减少了

critical
构造的同步开销,并以简化的方式显示了
reduction
子句的实际实现方式。


0
投票

你可以尝试“omp Critical”:

double max_calc_value = -DBL_MAX; // minimum double value
#pragma omp parallel for
for (int i = 20; i < 1000; i++) 
{
    a_value = my_slow_function(large_double_vector_array, param1*i, .., param5+i);
#pragma omp critical
    {
        if (a_value > max_calc_value){
            max_calc_value = a_value;
            i_max = i;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.