OpenMP 缩减:min 给出错误结果

RL-*_*L-S 1 c++ multithreading g++ openmp c++11

我想在循环parallel外部的区域中使用 OpenMP 缩减for。根据OpenMP 参考parallel,可以在区域中使用归约子句,因此不需要for循环 or 。sections

reduction (min:...)但是,当在某个区域使用 OpenMP 时parallel,我得到的结果不正确。但是,如果我对 a 使用完全相同的结构reduction (max:...),则结果是正确的。如果我使用循环进行最小减少(#pragma omp for reduction (min:...)),结果是正确的,但我认为这没有必要。这是我的代码:

#include <omp.h>
#include <iostream>
#include <limits>
#include <algorithm>

int main(){
    auto minVar { std::numeric_limits<int>::max() };
    auto maxVar { std::numeric_limits<int>::min() };
    auto minVarLoop { std::numeric_limits<int>::max() };

    #pragma omp parallel
    {
        int threadNo { omp_get_thread_num() };

        #pragma omp reduction (min:minVar)
        minVar = std::min(minVar, threadNo);
        // minVar = minVar < threadNo ? minVar : threadNo; // also doesn't work
        
        #pragma omp for reduction(min:minVarLoop)
        for (int i=0; i<omp_get_num_threads(); ++i){
            minVarLoop = std::min(minVarLoop, threadNo);
        }
        
        #pragma omp reduction (max:maxVar)
        maxVar = std::max(maxVar, threadNo);
    }
    std::cout
        <<   "min thread num: " << minVar
        << "\nmax thread num: " << maxVar
        << "\nmin thread num from Loop: " << minVarLoop
        << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

16 个线程的预期输出是

min thread num: 0
max thread num: 15
min thread num from Loop: 0
Run Code Online (Sandbox Code Playgroud)

我得到的输出是

min thread num: 12 // or any other number between 0 and 15
max thread num: 15
min thread num from Loop: 0
Run Code Online (Sandbox Code Playgroud)

我正在 Ubuntu 21.04 上使用 g++ 版本 10.3.0 进行编译,仅使用标志-fopenmp

我在忽略什么?

编辑:初始化minVar,即使用int minVar;某种方式使其工作,但我没有找到令人满意的解决方案。此外,尝试与 相同maxVar,会使这些结果不正确。天啊。

Mic*_*emm 5

您正在使用编译器尚不支持的功能。如果您编译代码,-Wall您将看到 GCC 10.3.0 显示此警告:

\n
red.cc:15: warning: ignoring \xe2\x80\x98#pragma omp reduction\xe2\x80\x99 [-Wunknown-pragmas]\n   15 |         #pragma omp reduction (min:minVar)\n      |\nred.cc:24: warning: ignoring \xe2\x80\x98#pragma omp reduction\xe2\x80\x99 [-Wunknown-pragmas]\n   24 |         #pragma omp reduction (max:maxVar)\n      |\n
Run Code Online (Sandbox Code Playgroud)\n

如果您更正代码,就像我在下面显示的那样使用正确的拼写(请参阅scope Construct),编译器仍然会反对,因为它还不支持 OpenMP API 5.1 版本:

\n
red.cc:15: warning: ignoring \xe2\x80\x98#pragma omp scope\xe2\x80\x99 [-Wunknown-pragmas]\n   15 |         #pragma omp scope reduction (min:minVar)\n      |\nred.cc:24: warning: ignoring \xe2\x80\x98#pragma omp scope\xe2\x80\x99 [-Wunknown-pragmas]\n   24 |         #pragma omp scope reduction (max:maxVar)\n      |\n
Run Code Online (Sandbox Code Playgroud)\n

正确的拼写如下:

\n
#include <omp.h>\n#include <iostream>\n#include <limits>\n#include <algorithm>\n\nint main(){\n    auto minVar { std::numeric_limits<int>::max() };\n    auto maxVar { std::numeric_limits<int>::min() };\n    auto minVarLoop { std::numeric_limits<int>::max() };\n\n    #pragma omp parallel\n    {\n        int threadNo { omp_get_thread_num() };\n\n        #pragma omp scope reduction (min:minVar)\n        minVar = std::min(minVar, threadNo);\n        // minVar = minVar < threadNo ? minVar : threadNo; // also doesn\'t work\n        \n        #pragma omp for reduction(min:minVarLoop)\n        for (int i=0; i<omp_get_num_threads(); ++i){\n            minVarLoop = std::min(minVarLoop, threadNo);\n        }\n        \n        #pragma omp scope reduction (max:maxVar)\n        maxVar = std::max(maxVar, threadNo);\n    }\n    std::cout\n        <<   "min thread num: " << minVar\n        << "\\nmax thread num: " << maxVar\n        << "\\nmin thread num from Loop: " << minVarLoop\n        << "\\n";\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

不同的结果是由于竞争条件造成的。不要问为什么你会得到正确的 max 结果,我运行代码时确实会随时得到不同的结果。

\n

代码的另一个正确版本(不需要 OpenMP API 5.1 版本的前沿支持)是这样的:

\n
#include <omp.h>\n#include <iostream>\n#include <limits>\n#include <algorithm>\n\nint main(){\n    auto minVar { std::numeric_limits<int>::max() };\n    auto maxVar { std::numeric_limits<int>::min() };\n    auto minVarLoop { std::numeric_limits<int>::max() };\n\n    #pragma omp parallel reduction(min:minVar) reduction(max:maxVar)\n    {\n        int threadNo { omp_get_thread_num() };\n\n        minVar = std::min(minVar, threadNo);\n\n        #pragma omp for reduction(min:minVarLoop)\n        for (int i=0; i<omp_get_num_threads(); ++i){\n            minVarLoop = std::min(minVarLoop, threadNo);\n        }\n\n        maxVar = std::max(maxVar, threadNo);\n    }\n    std::cout\n        <<   "min thread num: " << minVar\n        << "\\nmax thread num: " << maxVar\n        << "\\nmin thread num from Loop: " << minVarLoop\n        << "\\n";\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n