基于boost::thread_group的点云程序并行化改造后运行崩溃问题
问题排查与解决方案
看起来你这个多线程改造踩了两个典型的坑,直接导致了崩溃,咱们一步步来分析和修复:
核心问题分析
1. 线程数量爆炸(最致命的问题)
你给每一个点都创建了一个线程——17000个点就开17000个线程!这完全违背了多线程的设计逻辑:
- 系统的线程资源是有限的,每个线程默认会占用几MB的栈内存,17000个线程的内存需求轻松突破几十GB,直接触发内存耗尽或者系统无法创建线程的错误。
- 这么多线程会让CPU的调度开销急剧飙升,实际执行效率甚至会比单线程还低,完全失去了并行化的意义。
2. 无保护的并发容器写入
多个线程同时对std::vector<Point3D>& relevant_points进行写入操作(比如push_back),但std::vector本身不是线程安全容器。并发写入会破坏它的内部结构(比如扩容时的内存拷贝、size/end指针的原子性修改),这也是崩溃的高频诱因。
修复方案
方案一:分块并行(控制线程数量)
不要给每个点开线程,而是根据CPU核心数把点云分成若干块,每块交给一个线程处理。这样既控制了线程数量,又能充分利用多核CPU的优势。
修改后的示例代码:
void Estimator::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) { std::cout << "pointcloud size = " << pointcloud.size() << std::endl; boost::thread_group group; // 根据CPU核心数确定线程数(也可以手动指定,比如4、8) const int thread_count = std::thread::hardware_concurrency(); const int points_per_thread = pointcloud.size() / thread_count; // 为每个线程分配点云块 for (int t = 0; t < thread_count; ++t) { int start_idx = t * points_per_thread; // 最后一个线程处理剩余所有点,避免丢点 int end_idx = (t == thread_count - 1) ? pointcloud.size() : (t + 1) * points_per_thread; group.create_thread(boost::bind(&Estimator::extract_relevant_points_block, this, start_idx, end_idx, boost::ref(relevant_points), boost::ref(pointcloud), boost::cref(cell_min_angle_sensor_rot), boost::cref(cell_max_angle_sensor_rot))); } group.join_all(); std::cout << "All threads finished" << std::endl; } // 单个线程处理一块点云的函数 void Estimator::extract_relevant_points_block(int start_idx, int end_idx, std::vector<Point3D>& relevant_points, std::vector<Point3D>& pointcloud, doubleIE cell_min_angle_sensor_rot, doubleIE cell_max_angle_sensor_rot) { // 先把结果存在线程局部容器里,减少锁竞争 std::vector<Point3D> local_relevant; for (int i = start_idx; i < end_idx; ++i) { const Point3D& p = pointcloud[i]; // 这里放你的点云筛选逻辑 if (/* 满足角度条件的判断 */) { local_relevant.push_back(p); } } // 最后用锁保护,把局部结果合并到全局容器 static boost::mutex mtx; boost::lock_guard<boost::mutex> lock(mtx); relevant_points.insert(relevant_points.end(), local_relevant.begin(), local_relevant.end()); }
方案二:强制线程安全(必须执行)
不管用哪种并行方式,只要多个线程要写入同一个共享容器,就必须用同步机制保护:
- 上面的示例用了局部容器+批量合并的方式,把锁的使用频率降到最低,效率比每次写入都加锁要高得多。
- 如果一定要实时写入全局容器,那每次操作都要加锁:
// 在线程函数中写入全局容器时 static boost::mutex mtx; boost::lock_guard<boost::mutex> lock(mtx); relevant_points.push_back(p);
额外注意事项
- 确保
pointcloud在多线程处理过程中是只读的(你的代码里是传入引用,只要没有其他线程修改它就没问题)。 - 如果你的点云处理逻辑里还有其他共享资源操作,也要同步保护。
- 若项目允许,建议改用C++11及以后的标准库线程(
std::thread、std::mutex),比boost线程更通用。
内容的提问来源于stack exchange,提问作者tony497
相关产品推荐
相关产品推荐

