You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程操作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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:01:12