OpenMP min reduction和std :: min

时间:2016-09-08 14:30:02

标签: c++ openmp min

我正在测试OpenMP min reduction。如果我编写如下代码,它将返回正确的结果:res = 3。

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

int main(){

    omp_set_num_threads(5);

    float res=10;

#pragma omp parallel for default(shared) reduction(min:res)
    for(int i1 = 0; i1 <= 10; i1++)
        for(int i0 = 0; i0 <= 10; i0++)
            if(res > 3.0+i1+20*i0)
                res = 3.0+i1+20*i0;

    std::cout << "res = " << res << std::endl;

    return 0;
}

但是,如果我通过替换&#34;以及#34;使用&#34; std :: min&#34;语句,然后结果是错误的:res = 10。

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

int main(){

    omp_set_num_threads(5);

    float res=10;

#pragma omp parallel for default(shared) reduction(min:res)
    for(int i1 = 0; i1 <= 10; i1++)
        for(int i0 = 0; i0 <= 10; i0++)
            res = std::min(res,static_cast<float>(3.0+i1+20*i0));

    std::cout << "res = " << res << std::endl;

    return 0;
}

OpenMP min reduce是否会干扰std :: min?

3 个答案:

答案 0 :(得分:1)

首先,您的代码符合要求:并行内部的代码类型无关紧要。

reduction子句暗示的是每个线程都有自己的私有副本初始化为min运算符的中性元素(即减少项类型中最大的可表示数字),它们将使用它直到构造结束。此时,这些私有副本将使用reduction标识符缩减为原始列表项,在您的情况下,该标识符为min运算符。所以这里没有竞争条件。

我使用与您相同的版本执行了您的代码,并且工作正常:icpc (ICC) 16.0.0和OpenMP版本201307。这个问题可能与你正在使用的C ++标准头有关吗?

答案 1 :(得分:-1)

我会在得出结论之前交换循环。 在类似的上下文中,我发现了必要的单独的内部和外部环路减少变量。 -std :: min适用于icpc,但不适用于g ++或msvc

答案 2 :(得分:-1)

问题是你有数据竞争。

在第一个示例中,OpenMP运行时计算所有线程中的最小值:每个线程都有自己的res,运行时确定最小值。运行时确保所有线程都能正确读取和写入res

在第二个示例中,每个线程都在调用std::min以确定res与另一个值之间的最小值。由于您的res子句,shareddefault(shared),因此所有线程都会尝试同时使用和更新res,这是一场数据争用。

你应该坚持你的第一个例子。如果要使用std::min,则必须使用锁或类似的东西阻止数据竞争。