我意识到减少仅适用于C ++中的POD类型。您将如何实现复杂类型累加器的减少?
complex<double> x(0.0,0.0), y(1.0,1.0);
#pragma omp parallel for reduction(+:x)
for(int i=0; i<5; i++)
{
x += y;
}
(注意我可能已经遗漏了一些语法)。似乎一个明显的解决方案是将真实和虚构的组件分成临时双打,然后累积在那些组件上。我想我正在寻找优雅,这似乎......不仅仅是漂亮。这会是典型的方法吗?
答案 0 :(得分:9)
在OpenMP中没有用户定义的减少的典型的解决方法甚至比你建议的更加丑陋。通常,在并行区域之前,人们创建一个(至少)元素的数组,就像区域中有线程一样,使用omp_get_thread_num()
作为数组的索引,为每个线程分别累积部分结果,并且在平行区域之后的循环中累积结果的最终减少。
据我所知,OpenMP语言委员会致力于为规范添加用户定义的缩减,因此最终可能会在几年后解决。
答案 1 :(得分:4)
很抱歉,OpenMP目前根本不支持。不幸的是,你需要以你已经描述过的丑陋方式进行并行缩减。
但是,如果这种并行缩减非常频繁,我想在TBB中创建一个类似于parallel_reduce
的构造函数。这种结构的实施是相当直接的。 Cilk plus有一个更强大的reducer对象,但我没有检查它是否支持非POD。
仅供参考,这种限制也可以在threadprivate
pragma中找到。我已经使用VC ++ 2008/2010和英特尔编译器(icc)进行了测试。 VC ++不能支持带有构造函数或析构函数的结构/类的threadprivate
(或者需要初始化函数调用的标量变量),抛出错误:error C3057,“动态初始化'threadprivate'符号“。您也可以阅读this MSDN link。但是,对于C3057的情况,icc是可以的。你可以看到,至少两个主要的实现是如此不同。
我认为支持非POD的并行减少会产生类似的问题。为了支持并行缩减,每个并行部分应为减少变量分配线程局部变量。因此,如果给定的减少变量是非POD,它们可能需要调用用户定义的构造函数。这就是我在C3057的情况下提到的相同问题。