从OpenMP 4.0开始,支持用户定义的还原。所以我正是从这里定义了C ++中std :: vector的简化。它可以在GNU / 5.4.0和GNU / 6.4.0上正常工作,但是对于intel / 2018.1.163的缩减,它返回随机值。
这是示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include "omp.h"
#pragma omp declare reduction(vec_double_plus : std::vector<double> : \
std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>())) \
initializer(omp_priv = omp_orig)
int main() {
omp_set_num_threads(4);
int size = 100;
std::vector<double> w(size,0);
#pragma omp parallel for reduction(vec_double_plus:w)
for (int i = 0; i < 4; ++i)
for (int j = 0; j < w.size(); ++j)
w[j] += 1;
for(auto i:w)
if(i != 4)
std::cout << i << std::endl;
return 0;
}
每个线程向所有w个条目(其本地w)加1,最后将它们全部加在一起(归约)。对于所有w条目,GNU的结果是4,而intel编译器的结果是随机的。有人知道这里发生了什么吗?
这似乎是英特尔编译器中的错误,我可以使用不涉及向量的C示例可靠地重现该错误:
#include <stdio.h>
void my_sum_fun(int* outp, int* inp) {
printf("%d @ %p += %d @ %p\n", *outp, outp, *inp, inp);
*outp = *outp + *inp;
}
int my_init(int* orig) {
printf("orig: %d @ %p\n", *orig, orig);
return *orig;
}
#pragma omp declare reduction(my_sum : int : my_sum_fun(&omp_out, &omp_in) initializer(omp_priv = my_init(&omp_orig))
int main()
{
int s = 0;
#pragma omp parallel for reduction(my_sum : s)
for (int i = 0; i < 2; i++)
s+= 1;
printf("sum: %d\n", s);
}
输出:
orig: 0 @ 0x7ffee43ccc80
0 @ 0x7ffee43ccc80 += 1 @ 0x7ffee43cc780
orig: 1 @ 0x7ffee43ccc80
1 @ 0x7ffee43ccc80 += 2 @ 0x2b56d095ca80
sum: 3
在从原始值初始化私有副本之前,它将归约操作应用于原始变量。这会导致错误的结果。
您可以手动添加障碍作为解决方法:
#pragma omp parallel reduction(vec_double_plus : w)
{
#pragma omp for
for (int i = 0; i < 4; ++i)
for (int j = 0; j < w.size(); ++j)
w[j] += 1;
#pragma omp barrier
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句