OpenMP 并行缩减(最小)不正确的结果
OpenMP parallel reduction (min) incorrect result
我正在使用 OpenMP reduction(min) 在所有参与线程的并行部分中获得最少的锁获取次数。
在并行部分内打印每个线程计数器时,我得到了正确的结果,但在并行部分之后,最小计数器为 0。
这是代码:
int counter = 0, maxV, minV;
bool _continue = true; //variable to indicate when one second is over
#pragma omp parallel private(id) shared(lock, _continue) reduction(min:minV) reduction(+:counter) reduction(max:maxV)
{
id = omp_get_thread_num();
if(id == 0)
{
auto start = std::chrono::high_resolution_clock::now(); //start time measurement
while(_continue)
{
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::micro> elapsed = finish - start;
if(elapsed.count() > std::chrono::microseconds(sec).count())
{
_continue = false;
}
}
}
else
{
while(_continue) //during timeframe, try to obtain lock as often as possible
{
lock.lock(id);
lock.unlock(id);
counter++;
}
minV = counter;
maxV = counter;
}
#pragma omp critical
{
std::cout << id << ": " << minV << std::endl;
}
}
std::cout << minV << std::endl;
典型的输出是这样的:
0: 2147483647
7: 256985
4: 255973
1: 256975
6: 255740
5: 256658
3: 256856
2: 256943
0
因此,即使对于线程 0,即不获取锁而只是占用时间的线程,minV 也被正确初始化为缩减列表项类型 (int) 中的最大可表示数。
根据我选择的编译器选项,我可以将 minV 的结果(cout 中的最后一行)更改为以下值(总是错误...):
minV = 32767 | -std=c++14 -fopenmp
最小电压 = 0 | -std=c++14 -fopenmp -O3
minV = 32766 | -std=c++14 -fopenmp -Wall
minV = 32767 | -std=c++14 -fopenmp -Wall -pedantic -march=native -fconcepts
所以我认为它与我的编译器选项有关?奇怪的是,最大和总和的减少似乎工作正常......
感谢任何帮助。
您混淆了 OMP 内部使用的初始值和来自用户代码的初始值。部分减少是用内部值完成的,但在某些时候还必须减少 user-supplied 初始值。如果你不设置它,任何事情都可能发生。
这是一张可爱的照片:https://theartofhpc.com/pcse/omp-reduction.html#Initialvalueforreductions
我正在使用 OpenMP reduction(min) 在所有参与线程的并行部分中获得最少的锁获取次数。 在并行部分内打印每个线程计数器时,我得到了正确的结果,但在并行部分之后,最小计数器为 0。 这是代码:
int counter = 0, maxV, minV;
bool _continue = true; //variable to indicate when one second is over
#pragma omp parallel private(id) shared(lock, _continue) reduction(min:minV) reduction(+:counter) reduction(max:maxV)
{
id = omp_get_thread_num();
if(id == 0)
{
auto start = std::chrono::high_resolution_clock::now(); //start time measurement
while(_continue)
{
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::micro> elapsed = finish - start;
if(elapsed.count() > std::chrono::microseconds(sec).count())
{
_continue = false;
}
}
}
else
{
while(_continue) //during timeframe, try to obtain lock as often as possible
{
lock.lock(id);
lock.unlock(id);
counter++;
}
minV = counter;
maxV = counter;
}
#pragma omp critical
{
std::cout << id << ": " << minV << std::endl;
}
}
std::cout << minV << std::endl;
典型的输出是这样的:
0: 2147483647
7: 256985
4: 255973
1: 256975
6: 255740
5: 256658
3: 256856
2: 256943
0
因此,即使对于线程 0,即不获取锁而只是占用时间的线程,minV 也被正确初始化为缩减列表项类型 (int) 中的最大可表示数。
根据我选择的编译器选项,我可以将 minV 的结果(cout 中的最后一行)更改为以下值(总是错误...):
minV = 32767 | -std=c++14 -fopenmp
最小电压 = 0 | -std=c++14 -fopenmp -O3
minV = 32766 | -std=c++14 -fopenmp -Wall
minV = 32767 | -std=c++14 -fopenmp -Wall -pedantic -march=native -fconcepts
所以我认为它与我的编译器选项有关?奇怪的是,最大和总和的减少似乎工作正常......
感谢任何帮助。
您混淆了 OMP 内部使用的初始值和来自用户代码的初始值。部分减少是用内部值完成的,但在某些时候还必须减少 user-supplied 初始值。如果你不设置它,任何事情都可能发生。
这是一张可爱的照片:https://theartofhpc.com/pcse/omp-reduction.html#Initialvalueforreductions