OpenMP 缩减:min 给出不正确的结果
OpenMP reduction: min gives incorrect result
我想在 parallel
区域、for
循环之外使用 OpenMP 缩减。根据 OpenMP reference,可以在 parallel
区域使用缩减子句,因此不需要 for
循环或 sections
。
但是,在 parallel
区域使用 OpenMP reduction (min:...)
时,我得到的结果不正确。但是,如果我对 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;
}
16 个线程的预期输出是
min thread num: 0
max thread num: 15
min thread num from Loop: 0
我得到的输出是
min thread num: 12 // or any other number between 0 and 15
max thread num: 15
min thread num from Loop: 0
我在 Ubuntu 21.04 上使用 g++ 版本 10.3.0 进行编译,仅使用标志 -fopenmp
.
我忽略了什么?
编辑:不是初始化minVar
,即使用int minVar;
以某种方式使其工作,但我没有找到令人满意的解决方案。此外,尝试对 maxVar
进行相同的操作会使 those 结果不正确。天啊
您正在使用编译器尚不支持的功能。如果您使用 -Wall
编译代码,您将看到 GCC 10.3.0 显示此警告:
red.cc:15: warning: ignoring ‘#pragma omp reduction’ [-Wunknown-pragmas]
15 | #pragma omp reduction (min:minVar)
|
red.cc:24: warning: ignoring ‘#pragma omp reduction’ [-Wunknown-pragmas]
24 | #pragma omp reduction (max:maxVar)
|
如果您更正代码,就像我在下面显示的那样使用正确的拼写(参见 scope Construct),编译器仍然会反对,因为它不支持 OpenMP 5.1 版 API还有:
red.cc:15: warning: ignoring ‘#pragma omp scope’ [-Wunknown-pragmas]
15 | #pragma omp scope reduction (min:minVar)
|
red.cc:24: warning: ignoring ‘#pragma omp scope’ [-Wunknown-pragmas]
24 | #pragma omp scope reduction (max:maxVar)
|
正确的拼写应该是这样的:
#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 scope 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 scope 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;
}
不同的结果是由于竞争条件造成的。不要问为什么你得到的最大结果是正确的,我每次都会得到不同的结果,我 运行 代码。
您的代码的另一个正确版本(不需要对 OpenMP 5.1 API 版的前沿支持)是这样的:
#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 reduction(min:minVar) reduction(max:maxVar)
{
int threadNo { omp_get_thread_num() };
minVar = std::min(minVar, threadNo);
#pragma omp for reduction(min:minVarLoop)
for (int i=0; i<omp_get_num_threads(); ++i){
minVarLoop = std::min(minVarLoop, threadNo);
}
maxVar = std::max(maxVar, threadNo);
}
std::cout
<< "min thread num: " << minVar
<< "\nmax thread num: " << maxVar
<< "\nmin thread num from Loop: " << minVarLoop
<< "\n";
return 0;
}
我想在 parallel
区域、for
循环之外使用 OpenMP 缩减。根据 OpenMP reference,可以在 parallel
区域使用缩减子句,因此不需要 for
循环或 sections
。
但是,在 parallel
区域使用 OpenMP reduction (min:...)
时,我得到的结果不正确。但是,如果我对 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;
}
16 个线程的预期输出是
min thread num: 0
max thread num: 15
min thread num from Loop: 0
我得到的输出是
min thread num: 12 // or any other number between 0 and 15
max thread num: 15
min thread num from Loop: 0
我在 Ubuntu 21.04 上使用 g++ 版本 10.3.0 进行编译,仅使用标志 -fopenmp
.
我忽略了什么?
编辑:不是初始化minVar
,即使用int minVar;
以某种方式使其工作,但我没有找到令人满意的解决方案。此外,尝试对 maxVar
进行相同的操作会使 those 结果不正确。天啊
您正在使用编译器尚不支持的功能。如果您使用 -Wall
编译代码,您将看到 GCC 10.3.0 显示此警告:
red.cc:15: warning: ignoring ‘#pragma omp reduction’ [-Wunknown-pragmas]
15 | #pragma omp reduction (min:minVar)
|
red.cc:24: warning: ignoring ‘#pragma omp reduction’ [-Wunknown-pragmas]
24 | #pragma omp reduction (max:maxVar)
|
如果您更正代码,就像我在下面显示的那样使用正确的拼写(参见 scope Construct),编译器仍然会反对,因为它不支持 OpenMP 5.1 版 API还有:
red.cc:15: warning: ignoring ‘#pragma omp scope’ [-Wunknown-pragmas]
15 | #pragma omp scope reduction (min:minVar)
|
red.cc:24: warning: ignoring ‘#pragma omp scope’ [-Wunknown-pragmas]
24 | #pragma omp scope reduction (max:maxVar)
|
正确的拼写应该是这样的:
#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 scope 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 scope 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;
}
不同的结果是由于竞争条件造成的。不要问为什么你得到的最大结果是正确的,我每次都会得到不同的结果,我 运行 代码。
您的代码的另一个正确版本(不需要对 OpenMP 5.1 API 版的前沿支持)是这样的:
#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 reduction(min:minVar) reduction(max:maxVar)
{
int threadNo { omp_get_thread_num() };
minVar = std::min(minVar, threadNo);
#pragma omp for reduction(min:minVarLoop)
for (int i=0; i<omp_get_num_threads(); ++i){
minVarLoop = std::min(minVarLoop, threadNo);
}
maxVar = std::max(maxVar, threadNo);
}
std::cout
<< "min thread num: " << minVar
<< "\nmax thread num: " << maxVar
<< "\nmin thread num from Loop: " << minVarLoop
<< "\n";
return 0;
}