C++:使用 OpenMP 插入 std::vector
Posted
技术标签:
【中文标题】C++:使用 OpenMP 插入 std::vector【英文标题】:C++: std::vector insert with OpenMP 【发布时间】:2022-01-18 06:08:58 【问题描述】:我在以下函数中遇到分段错误,该函数使用向量插入与 OpenMP 并行创建点网格。
std::vector<n_point_t> fill_points(size_t Nn1, size_t Nn2)
std::vector<n_point_t> grid;
grid.reserve(Nn1*Nn2);
#pragma omp parallel for
for (size_t i=0; i<Nn1; i++)
std::vector<n_point_t> subgrid = get_subgrid(Nn2);
grid.insert(grid.begin()+i*Nn2, subgrid.begin(), subgrid.end());
return grid;
n_point_t
定义为
union n_point_t
double coords[6];
struct
double n1x;
double n1y;
double n1z;
double n2x;
double n2y;
double n2z;
;
;
而get_subgrid(size_t Nn2)
创建一个n_point_t
大小为Nn2
的网格。
插入肯定是造成分段错误的原因。我不明白这里的问题。由于插入索引,每个线程都应该插入grid
的不同部分。
即使我使用 #pragma omp critical
保护插入,我也会遇到分段错误。
【问题讨论】:
这是一个非常糟糕的主意。向量插入会修改向量的内容并使迭代器无效。当您执行begin() + i * Nn2
时,您还使用了可能已经结束的迭代器。为什么不预先分配向量并让您的函数就地填充值?
我不是已经用reserve()
预先分配了吗?我是 C++ 新手,这大致就是我在 python 中使用 numpy 数组的方式。如果我为向量保留高达Nn1*Nn2
,begin() + i * Nn2
怎么会超过向量的末尾?我之所以这样写,是因为我希望 get_subgrid()
可供此代码的用户使用,如果他们想自己自定义构建网格。
你分配了 容量 但向量仍然包含零个元素,所以begin() == end()
。插入是将元素添加到向量中。尝试resize
而不是reserve
,然后就地复制数据而不是使用insert
。此外,您确定(来自代码分析)对于这个简单的数组初始化,使用 OpenMP 会更快吗?在我看来,你做了很多不必要的分配,然后你也有线程同步的开销,这可能会被一个天真的单线程初始化程序打败,除非你的 subgrid 调用很昂贵。
我明白了!我认为reserve()
类似于np.empty()
。我可以使用调整大小。老实说,我将其作为一个实践问题并行化,以解决使用 OpenMP 构建的任何问题,并练习我多年前学习的 OpenMP。我将在项目的其他点需要 OpenMP,但在这里并不是必需的。感谢您的帮助!
【参考方案1】:
由于您提前致电reserve()
,因此这里不会发生重新分配。但是你将一个危险的论点grid.begin()+i*Nn2
传递给insert
。不保证它是有效的迭代器。
如果subgrid
的长度小于N2
怎么办?你会得到一个不连续的向量吗?请不要这样做。它在单个线程中工作,只是因为 grid.begin()+i*Nn2
恰好是有效的。换句话说,不要试图去触碰向量中未使用的内存。
一个建议的解决方案可能是resize()
向量,如果您必须使用多个线程,请分配它们。
【讨论】:
以上是关于C++:使用 OpenMP 插入 std::vector的主要内容,如果未能解决你的问题,请参考以下文章
NodeJS:具有多线程的本机 C++ 模块(openmp)