我正在测试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?
答案 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
子句,shared
为default(shared)
,因此所有线程都会尝试同时使用和更新res
,这是一场数据争用。
你应该坚持你的第一个例子。如果要使用std::min
,则必须使用锁或类似的东西阻止数据竞争。