当前位置: 首页 > news >正文

【记录】C++生产者 / 消费者 案例

一、实现流程

1. 定义线程安全的队列结构

需要封装std::queue,用std::mutex保证互斥访问,用std::condition_variable触发唤醒:

#include <queue>
#include <mutex>
#include <condition_variable>
#include <opencv2/opencv.hpp>  // 假设用OpenCV存储图像// 线程安全的图像队列
class ImageQueue {
private:std::queue<cv::Mat> queue_;       // 存储图像数据std::mutex mtx_;                  // 互斥锁,保护队列操作std::condition_variable cv_;      // 条件变量,用于线程同步bool is_stopped_ = false;         // 退出标志(用于优雅终止线程)public:// 生产者调用:放入图像void push(const cv::Mat& img) {std::lock_guard<std::mutex> lock(mtx_);  // 自动加锁/解锁queue_.push(img);cv_.notify_one();  // 通知等待的消费者(唤醒一个线程)}// 消费者调用:取出图像(无数据时阻塞)bool pop(cv::Mat& img) {std::unique_lock<std::mutex> lock(mtx_);  // 可手动解锁的锁// 等待条件:队列非空 或 线程需终止cv_.wait(lock, [this]{ return !queue_.empty() || is_stopped_; });if (is_stopped_) return false;  // 线程终止,退出img = queue_.front();queue_.pop();return true;}// 终止线程时调用void stop() {std::lock_guard<std::mutex> lock(mtx_);is_stopped_ = true;cv_.notify_all();  // 唤醒所有等待的线程}
};
2. 实现生产者线程(相机采集)

生产者的核心是快速获取图像并放入队列,避免在回调 / 采集函数中做耗时操作:

#include <thread>
#include <相机SDK头文件>  // 替换为实际相机SDKImageQueue img_queue;  // 全局队列(或通过指针传递)
bool is_running = true;// 相机回调函数(生产者的核心逻辑)
void cameraCallback(const CameraImage& raw_img) {if (!is_running) return;// 轻量操作:将原始图像转为OpenCV格式(快速转换,避免复杂计算)cv::Mat img(raw_img.height, raw_img.width, CV_8UC3, raw_img.data);// 放入队列(耗时极短)img_queue.push(img);
}// 启动相机采集线程
void startProducer() {// 初始化相机(根据SDK文档配置)Camera::init();Camera::setCallback(cameraCallback);  // 设置回调Camera::startCapture();  // 开始采集(如30fps)// 保持线程运行(或由SDK内部线程驱动)while (is_running) {std::this_thread::sleep_for(std::chrono::milliseconds(100));}Camera::stopCapture();Camera::release();
}
3. 实现消费者线程(图像处理)

消费者从队列中取图并处理,处理速度慢也不会阻塞生产者(队列会暂存数据):

// 图像处理函数(耗时操作)
void processImage(const cv::Mat& img) {cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);  // 示例:转灰度cv::GaussianBlur(gray, gray, cv::Size(5,5), 0);  // 高斯模糊// ... 其他耗时操作(如目标检测、特征提取等)
}// 消费者线程
void startConsumer() {cv::Mat img;while (img_queue.pop(img)) {  // 无数据时阻塞,不占用CPUprocessImage(img);  // 处理图像(耗时操作)}
}
4. 主线程控制启动与退出
int main() {// 启动生产者和消费者线程std::thread producer_thread(startProducer);std::thread consumer_thread(startConsumer);// 运行一段时间(或等待用户输入退出)std::cout << "按Enter键退出..." << std::endl;std::cin.get();// 终止流程is_running = false;          // 停止生产者img_queue.stop();            // 通知消费者退出producer_thread.join();      // 等待生产者线程结束consumer_thread.join();      // 等待消费者线程结束return 0;
}

二、关键优势

  1. 避免 CPU 空转:消费者无数据时通过cv.wait()进入休眠,不占用 CPU;生产者放入数据后通过cv.notify_one()唤醒,仅在必要时工作。
  2. 解耦采集与处理:相机采集(快)和图像处理(慢)独立运行,采集线程不会被处理耗时阻塞,避免丢帧;处理线程也不会因采集速度快而超负荷。
  3. 灵活扩展:可根据需求增加多个消费者线程(如 2 个处理线程并行处理队列数据),充分利用多核 CPU:
    // 启动多个消费者线程
    std::vector<std::thread> consumers;
    for (int i = 0; i < 2; ++i) {consumers.emplace_back(startConsumer);
    }
    

三、注意事项

  1. 队列长度控制:若处理速度长期慢于采集速度,队列会无限增长导致内存溢出。可在push时增加限制:
    void push(const cv::Mat& img) {std::lock_guard<std::mutex> lock(mtx_);if (queue_.size() > 10) {  // 限制最大缓存10帧queue_.pop();  // 丢弃最旧的帧}queue_.push(img);cv_.notify_one();
    }
    

  2. 图像数据拷贝:若图像数据较大,push时的cv::Mat拷贝(浅拷贝,仅复制头信息)是高效的,但需确保原始数据生命周期足够长(避免相机 SDK 过早释放)。
  3. 线程安全:所有对队列的操作必须加锁,否则可能导致队列数据混乱或崩溃。
http://www.dtcms.com/a/297913.html

相关文章:

  • 刷题日记0725
  • 篇五 网络通信硬件之PHY,MAC, RJ45
  • PytorchLightning最佳实践基础篇
  • 谷歌母公司Alphabet发布超预期业绩,提高全年资本支出至850亿美元
  • 从 Elastic 到 ClickHouse:日志系统性能与成本优化之路
  • 【大模型实战】提示工程(Prompt Engineering)
  • 优秀案例:基于python django的智能家居销售数据采集和分析系统设计与实现,使用混合推荐算法和LSTM算法情感分析
  • 九联UNT413AS_晶晨S905L3S芯片_2+8G_安卓9.0_线刷固件包
  • 短剧小程序系统开发:构建影视娱乐生态新格局
  • Spring Boot License 认证系统
  • C#(数据类型)
  • k8s的存储之secerts
  • Python数据可视化利器:Matplotlib全解析
  • 智能制造——解读39页MOM数字化工厂平台解决方案【附全文阅读】
  • Linux网络配置全攻略:IP、路由与双机通信
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十天-准备项目中
  • 图的遍历:深度优先与广度优先
  • SpringBoot学习路径二--Spring Boot自动配置原理深度解析
  • Qt 状态机框架:复杂交互逻辑的处理
  • R 语言绘制六种精美热图:转录组数据可视化实践(基于 pheatmap 包)
  • 从零开始学习Dify-数据库数据可视化(五)
  • java的设计模式及代理模式
  • 负载均衡:提升业务性能的关键技术
  • Zabbix告警系统集成指南:从钉钉机器人到网易邮件的全流程配置
  • pytest-html 优势及与其他插件对比
  • 自动驾驶领域中的Python机器学习
  • VLA:自动驾驶的“新大脑”?
  • npm init vite-app runoob-vue3-test2 ,npm init vue@latest,指令区别
  • C语言第 9 天学习笔记:数组(二维数组与字符数组)
  • Java-Properties类和properties文件详解