我目前正在尝试使用openMP 2.0和Visual Studio 2012并行化最大值搜索。我觉得这个问题很简单,它可以用作教科书示例。但是,我遇到了一个我不明白的竞争状态。
有问题的代码段落是:
double globalMaxVal = std::numeric_limits<double>::min();;
#pragma omp parallel for
for(int i = 0; i < numberOfLoops; i++)
{
{/* ... */} // In this section I determine maxVal
// Besides reading out values from two std::vector via the [] operator, I do not access or manipulate any global variables.
#pragma omp flush(globalMaxVal) // IF I COMMENT OUT THIS LINE I RUN INTO A RACE CONDITION
#pragma omp critical
if(maxVal > globalMaxVal)
{
globalMaxVal = maxVal;
}
}
我不明白为什么有必要刷新globalMaxVal。 openMP 2.0文档声明:“以下指令隐含了一个没有变量列表的flush指令:[...]进入和退出关键[...]”然而,我得到的结果与非并行化实现,如果我省略了flush指令。
我意识到上面的代码可能不是解决我问题的最漂亮或最有效的方法,但目前我想了解,为什么我会看到这种竞争条件。
非常感谢任何帮助!
编辑:
下面我现在添加了一个最小,完整且可验证的示例,仅需要openMP和标准库。我已经能够使用此代码重现上述问题。
对我来说,如果省略flush指令,一些运行会产生一个globalMaxVal!= 99。使用该指令,它可以正常工作。
#include <algorithm>
#include <iostream>
#include <random>
#include <Windows.h>
#include <omp.h>
int main()
{
// Repeat parallelized code 20 times
for(int r = 0; r < 20; r++)
{
int globalMaxVal = 0;
#pragma omp parallel for
for(int i = 0; i < 100; i++)
{
int maxVal = i;
// Some dummy calculations to use computation time
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_real_distribution<double> particleDistribution(-1.0, 1.0);
for(int j = 0; j < 1000000; j++)
particleDistribution(generator);
// The actual code bit again
#pragma omp flush(globalMaxVal) // IF I COMMENT OUT THIS LINE I RUN INTO A RACE CONDITION
#pragma omp critical
if(maxVal > globalMaxVal)
{
globalMaxVal = maxVal;
}
}
// Report outcome - expected to be 99
std::cout << "Run: " << r << ", globalMaxVal: " << globalMaxVal << std::endl;
}
system("pause");
return 0;
}
编辑2:
经过进一步测试,我们发现在没有优化(/ Od)的情况下在Visual Studio中编译代码或在Linux中编译正确的结果,而Visual Studio 2012中的错误(Microsoft C / C ++编译器版本17.00.61030)激活优化(/ O2)。