Parallel processing 为什么我的openMP 2.0临界指令没有刷新?

Parallel processing 为什么我的openMP 2.0临界指令没有刷新?,parallel-processing,openmp,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++) { {/* ... */} //

我目前正在尝试使用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;
    }
}
double globalMaxVal=std::numeric_limits::min();;
#pragma-omp并行
for(int i=0;iglobalMaxVal)
{
globalMaxVal=maxVal;
}
}
我不明白为什么有必要冲洗globalMaxVal。openMP 2.0文档指出:“对于以下指令,不带变量列表的flush指令是隐含的:[…]在进入和退出临界[…]时。”然而,如果我忽略flush指令,我会得到与非并行化实现不同的结果

我意识到上面的代码可能不是解决我的问题的最漂亮或最有效的方法,但此刻我想理解,为什么我会看到这种竞争状况

任何帮助都将不胜感激

编辑:

下面我添加了一个最小的、完整的、可验证的示例,只需要openMP和标准库。我已经能够用这段代码重现上面描述的问题

对我来说,一些跑步会产生一个globalMaxVal!=99,如果我省略flush指令。有了指令,它就可以正常工作了

#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;
}
#包括
#包括
#包括
#包括
#包括
int main()
{
//重复并行代码20次
对于(int r=0;r<20;r++)
{
int globalMaxVal=0;
#pragma-omp并行
对于(int i=0;i<100;i++)
{
int maxVal=i;
//使用计算时间的一些虚拟计算
std::随机_装置rd;
std::mt19937发生器(rd());
标准:均匀分布-真实分布-粒子分布(-1.0,1.0);
对于(int j=0;j<1000000;j++)
粒子分布(发生器);
//请重新输入实际代码位
#pragma omp flush(globalMaxVal)//如果我注释掉这一行,我会遇到竞争条件
#pragma-omp-critical
如果(maxVal>globalMaxVal)
{
globalMaxVal=maxVal;
}
}
//报告结果-预计为99

std::cout如果您的描述是准确的,我会说这是实现中的一个bug。如果您能提供一个。谢谢您的回答!我已经在上面的原始问题中添加了一个最小的、完整的和可验证的示例。很抱歉,您的代码给出了正确的答案,无论是否使用
flush
指令(正如预期的那样)嗨,Gilles!你能告诉我你是如何编译代码的吗?我们发现在Visual Studio中不进行优化(/Od)或在Linux中编译代码会得到正确的结果,而在Visual Studio 2012中,通过激活优化(/O2)会出现错误。(我现在也在主要帖子中添加了此信息。)它应该可以工作,即使使用VS Express 2012,我也无法复制它,而且我会非常小心地使用一个会把事情搞砸的实现。同样遗憾的是,VS不支持缩减(最大值),这是您在这种情况下通常会使用的。如果您的描述准确,我会说这是实现中的一个错误。如果您能提供一个错误,那会更好。感谢您的回答!我在上面的原始问题中添加了一个最小的、完整的和可验证的示例。很抱歉,您的代码以您的智慧给出了正确的答案Hi Gilles,
flush
指令(如预期的那样)您好!您能告诉我您是如何编译代码的吗?我们发现,在Visual Studio中不进行优化(/Od)或在Linux中编译代码会得到正确的结果,而在Visual Studio 2012中,通过激活优化(/O2)会出现错误。(我现在也将此信息添加到了主帖子中。)它应该可以工作,即使使用VS Express 2012,我也无法复制它,而且我会非常小心地使用一个会弄糟这一点的实现。同样遗憾的是,VS不支持reduce(max),这是您通常在这种情况下使用的。