OpenMP min reduction and std::min

OpenMP min reduction and std::min

本文关键字:min std reduction OpenMP and      更新时间:2023-10-16

我正在测试OpenMP最小减少。如果我像下面这样编写代码,它将返回正确的结果: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;
}

但是如果我以另一种方式编写,将" If "语句替换为"std::min",那么结果是错误的: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降低干扰std::min?

首先,你的代码是符合标准的:不管你在并行语句中使用哪种类型的代码。

reduction子句意味着每个线程都有自己的私有副本,初始化为min操作符的中性元素(即约简项类型中最大的可表示数),并且它们将一直使用它直到构造结束。此时,这些私有副本将使用还原标识符(在您的示例中是min操作符)还原为原始列表项。所以这里没有竞争条件

我已经使用与您相同的版本执行了您的代码,它工作得很好:icpc (ICC) 16.0.0和OpenMP版本201307。这个问题是否与您正在使用的c++标准头文件有关?

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

问题是你有数据竞赛。

在您的第一个示例中,所有线程中的最小值由OpenMP运行时计算:每个线程获得自己的res,运行时确定最小值。运行时确保res被所有线程正确读写。

在第二个示例中,每个线程调用std::min来确定res和另一个值之间的最小值。resshared,因为你的default(shared)子句,所以所有的线程将试图同时使用和更新res,这是一个数据竞争。

您应该继续使用第一个示例。如果您想使用std::min,您必须使用锁或类似的东西来防止数据竞争。