在c++中简化复杂变量的OpenMP的优雅(和典型)解决方案

Elegant (and typical) workaround for OpenMP reduction on complex variable in C++?

本文关键字:典型 解决方案 OpenMP 复杂 变量 c++      更新时间:2023-10-16

我意识到缩减只适用于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;
}

(注意我可能遗漏了一些语法)。似乎一个显而易见的解决方案是将实分量和虚分量拆分为临时双精度,然后对它们进行累加。我想我追求的是优雅,而这似乎……不够漂亮。这是典型的做法吗?

在OpenMP中缺少用户定义缩减的情况下,典型的解决方案甚至比您建议的更难看。通常,在并行区域之前,人们创建一个包含(至少)与该区域中线程数量相等的元素的数组,使用omp_get_thread_num()作为数组的索引分别为每个线程累积部分结果,并在并行区域之后的循环中对累积结果进行最终减少。

据我所知,OpenMP语言委员会正致力于在规范中添加用户定义的缩减,所以这个问题可能会在几年内最终解决。

对不起,OpenMP目前根本不支持。不幸的是,您需要以您已经描述的一种丑陋的方式进行并行约简。

然而,如果这种并行约简真的很频繁,我想做一个类似于TBB中的parallel_reduce的构造函数。这种构造的实现相当直接。Cilk plus有一个更强大的reducer对象,但是我没有检查它是否支持非POD。

仅供参考,这种限制也可以在threadprivate pragma中找到。我已经测试了vc++ 2008/2010和英特尔编译器(icc)。vc++不能支持具有构造函数或析构函数(或需要初始化函数调用的标量变量)的结构/类的threadprivate,通过抛出错误:错误C3057,"'threadprivate'符号的动态初始化"。你也可以阅读这个MSDN链接。然而,icc对C3057的情况是可以接受的。您可以看到,至少有两种主要的实现是如此不同。

我想在非pod上支持并行缩减也会有类似的问题。为了支持并行缩减,每个并行段应该为缩减变量分配一个线程局部变量。因此,如果给定的缩减变量是非pod的,它们可能需要调用用户定义的构造函数。这就产生了我在C3057中提到的同样的问题。

相关文章: