为什么我的openMP 2.0关键指令没有刷新?

时间:2017-11-07 14:23:47

标签: parallel-processing openmp

我目前正在尝试使用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)。

0 个答案:

没有答案