用于非POD的openmp并行
openmp parallel for with non-PODs
我正在努力加快一个程序的速度,它的核心是一个看起来很琐碎的循环:
double sum=0.;
#pragma omp parallel for reduction(+:sum) // fails
for( size_t i=0; i<_S.size(); ++i ){
sum += _S[i].first* R(atoms,_S[i].second) ;
}
虽然循环本身很琐碎,但其中的对象不是POD:这里_S实际上是其中std::vector< std::pair<double, std::vector<size_t> > >
和R(...)
是某个对象的过载operator(...) const
。它的两个参数都限定为const
,这样调用就不会有任何副作用。
由于大约90%的运行时间都花在了这个调用中,所以如上所示,放入一个OpenMP杂注并享受两到三倍的加速似乎是一件简单的事情;但当然——代码在单个线程中工作正常,但在多个线程中给出了明显错误的结果:-)。
不存在数据依赖关系,_S
和R(...)
似乎都可以在线程之间安全共享,但它仍然会产生无意义的内容。
我真的很感激任何关于如何发现问题的建议。
UPD2:
想明白了。和所有的bug一样,这是微不足道的。R(...)
调用的是某种类型的operator()
:
class objR{
public:
objR(const size_t N){
_buffer.reserve(N);
};
double operator(...) const{
// do something, using the _buffer to store intermediaries
}
private:
std::vector<double> _buffer;
};
很明显,不同的线程同时使用_buffer
并将其搞砸。到目前为止,我的解决方案是分配更多的空间(内存不是问题,代码受CPU限制):
class objR{
public:
objR(const size_t N){
int nth=1;
#ifdef _OPENMP
nth=omp_get_max_threads();
#endif
_buffer.resize(N);
}
double operator(...) const{
int thread_id=0;
#ifdef _OPENMP
thread_id = omp_get_thread_num();
#endif
// do something, using the _buffer[thread_id] to store intermediaries
}
private:
std::vector< std::vector<double> > _buffer;
};
这似乎是正确的。尽管如此,由于这是我第一次涉足多线程领域,如果有知识渊博的人能评论是否有更好的方法,我将不胜感激。
访问_S[i].first
和_S[i].second
是完全安全的(不能保证atoms
的任何内容)。这意味着您对R
的函数调用一定是导致问题的原因。你需要了解R
是什么,并发布它在做什么。
在另一点上,以下划线和大写字符开头的名称是为实现保留的,您可以通过使用它们来调用未定义的行为。
相关文章:
- OpenMP:并行更新数组总是需要减少数组吗
- 如何使用OpenMP并行这两个循环
- 如何使用OpenMP并行化此矩阵时间矢量运算
- 两个连续的 OpenMP 并行区域会相互减慢速度
- 如何使用 OpenMP 并行化最近邻搜索
- OpenMP并行发送哪些元素
- 对于openMP来说,有什么建议可以将以下代码与openMP并行
- 是否可以使用OpenMP并行化一个列表,该列表可以在每次迭代中添加新元素
- std::lock_guard 在 OpenMP 并行中
- 使用与 openmp C++并行的循环计算矩阵中每一行的最小值
- 嵌套循环 OpenMP 并行化、私有索引还是公共索引?
- C++ openmp 并行计算计算错误的结果
- 在 C++ 中使用 OpenMP 并行化两个 for 循环不会提供更好的性能
- 我可以将映射迭代器与 OpenMP 并行使用吗?
- OpenMP C++:并行化 for 循环的负载不平衡
- Qimage setPixel with openmp 并行 for 不起作用
- 如何加快有序子句的 openmp 并行速度?
- 跨越多个函数/对象的OpenMP并行区域
- 使用 OpenMP 并行执行比串行执行 c++ 花费更长的时间,我计算执行时间是否正确?
- 尝试与 OpenMP 并行处理链表数据