多线程操作Vector:带条件点筛选的多线程实现技术问询
OpenMP多线程下向std::vector添加元素的正确实现
在OpenMP多线程环境下直接对std::vector调用push_back是有线程安全问题的——因为vector的内部结构(比如扩容时的内存分配、迭代器/指针更新)并不是线程安全的,多个线程同时操作会导致数据竞争,轻则数据错乱,重则程序崩溃。下面给你几种靠谱的实现方式,按需选择:
方式一:用临界区(Critical Section)包裹写入操作
这是最直接的实现,通过#pragma omp critical让同一时间只有一个线程能执行push_back操作,避免竞争:
void IntervalMapEstimator::extract_relevant_points_multithread(std::vector<Point3D>& relevant_points ,std::vector<Point3D>& pointcloud, doubleIE cell_min_angle_sensor_rot, doubleIE cell_max_angle_sensor_rot) { relevant_points.reserve(pointcloud.size()); #pragma omp parallel for shared(relevant_points, pointcloud, cell_min_angle_sensor_rot, cell_max_angle_sensor_rot) for (size_t i = 0; i < pointcloud.size(); ++i) { const Point3D& p = pointcloud[i]; // 替换成你的实际筛选条件:判断点是否在目标角度区间内 if (/* 比如:p.sensor_rot_angle >= cell_min_angle_sensor_rot && p.sensor_rot_angle <= cell_max_angle_sensor_rot */) { #pragma omp critical { relevant_points.push_back(p); } } } }
优缺点:实现简单,容易理解,但临界区会导致线程等待,当符合筛选条件的点数量较多时,性能会明显下降。
方式二:线程局部存储+全局合并(推荐)
这种方式让每个线程先在自己的局部vector里存筛选后的点,最后再一次性合并到全局vector中,大大减少锁竞争的次数,性能更优:
void IntervalMapEstimator::extract_relevant_points_multithread(std::vector<Point3D>& relevant_points ,std::vector<Point3D>& pointcloud, doubleIE cell_min_angle_sensor_rot, doubleIE cell_max_angle_sensor_rot) { relevant_points.reserve(pointcloud.size()); #pragma omp parallel { // 每个线程创建独立的局部vector,预分配空间减少扩容开销 std::vector<Point3D> local_points; local_points.reserve(pointcloud.size() / omp_get_num_threads() + 1); #pragma omp for for (size_t i = 0; i < pointcloud.size(); ++i) { const Point3D& p = pointcloud[i]; if (/* 你的筛选条件 */) { local_points.push_back(p); } } // 合并局部数据到全局vector,仅此处需要临界区 #pragma omp critical { relevant_points.insert(relevant_points.end(), local_points.begin(), local_points.end()); } } }
优缺点:性能表现最好,尤其是在筛选比例较高的场景下;唯一的小开销是最后合并时的内存拷贝,但相比频繁的锁等待可以忽略不计。预分配局部vector的空间还能进一步提升效率。
方式三:使用C++17并行算法(备选)
如果你的项目支持C++17及以上,可以直接用标准库的并行std::copy_if,无需手动管理OpenMP线程:
#include <algorithm> #include <execution> void IntervalMapEstimator::extract_relevant_points_multithread(std::vector<Point3D>& relevant_points ,std::vector<Point3D>& pointcloud, doubleIE cell_min_angle_sensor_rot, doubleIE cell_max_angle_sensor_rot) { relevant_points.clear(); relevant_points.reserve(pointcloud.size()); std::copy_if(std::execution::par, pointcloud.begin(), pointcloud.end(), std::back_inserter(relevant_points), [&](const Point3D& p) { // 你的筛选条件 return p.sensor_rot_angle >= cell_min_angle_sensor_rot && p.sensor_rot_angle <= cell_max_angle_sensor_rot; }); }
优缺点:代码最简洁,无需手动处理线程同步,但需要编译器支持C++17并行算法,且可能需要链接第三方并行库(比如Intel TBB)。
额外注意事项
- 确保你的筛选条件计算是线程安全的:比如访问
Point3D的成员时是只读操作,没有其他线程同时修改这些数据。 - 提前调用
reserve给全局vector分配足够空间,避免多次扩容带来的开销和线程安全风险。
内容的提问来源于stack exchange,提问作者tony497
相关产品推荐
相关产品推荐

