多线程并发处理模式详解

目录

1.worker-object模式

2.双缓冲模式

3.生产者-消费者模式

4.主从模式

5.管道模式


以取像-显示举例说明如下:

1.worker-object模式

核心思想:Worker描述"做什么 ",Thread描述"在哪里做"

工作原理:

  1. 创建一个继承自 QObject 的类(Worker),把所有耗时逻辑写成它的槽函数;
  2. 创建一个普通的 QThread 实例;
  3. 使用 worker->moveToThread(thread),此时 Worker 的所有槽函数都会在子线程中执行。

举例:

cpp 复制代码
//Worker类:处理逻辑
class CameraWorker : public QObject 
{
    Q_OBJECT
public slots:
    void doGrab() 
    {
        while (m_running) 
        {
            cv::Mat frame = m_cam.read(); 
            emit sigNewFrame(frame);    
        }
    }
private:
    bool m_running = true;
};

//Thread决定在哪里做
void ImgPreview::start() 
{
    QThread* th = new QThread;
    CameraWorker* worker = new CameraWorker;
    worker->moveToThread(th); // 核心:移交执行权
    connect(th, &QThread::started, worker, &CameraWorker::doGrab);
    th->start();
}

2.双缓冲模式

核心思想:空间换时间,消除竞争。使用两块独立的内存区域,实现读与写的完全并行

工作原理:

  1. 后缓冲区:供写入线程使用,负责接收新数据。
  2. 前缓冲区:供读取线程使用,负责渲染或分析。
  3. 交换 :当后台写完且前台读完时,瞬间交换指针,两者始终不在同一块物理内存上争抢。

举例:

cpp 复制代码
class DoubleBuffer 
{
    cv::Mat buffers[2];
    int writeIdx = 0;	//写入和读取的下标是动态变化的
    QMutex mutex;

public:
    void update(cv::Mat& newFrame) 
	{
        // 相机写入"后方"缓冲区
        newFrame.copyTo(buffers[writeIdx]);	//向0写入(copy操作在锁外,效率更高)
        QMutexLocker locker(&mutex);
        writeIdx = !writeIdx; // 变更索引,下次向变更后的索引1中写入图像
    }
    cv::Mat getForDisplay() 
	{
        QMutexLocker locker(&mutex);
        return buffers[!writeIdx]; // UI读取"前方"缓冲区(读取0的图像)
    }
};

3.生产者-消费者模式

核心思想:解耦与缓冲。通过一个中间容器(队列)平衡数据产生和数据处理速度不匹配的问题。

工作原理:

  1. 生产者线程:负责生成数据(如采集图像)并存入阻塞队列。
  2. 消费者线程:负责从队列中取出数据并处理(如识别算法)。
  3. 缓冲区:当队列满时,生产者挂起;当队列空时,消费者挂起。

举例:

cpp 复制代码
QQueue<cv::Mat> imageQueue;
QWaitCondition condition;
QMutex mutex;

// 生产者线程(相机)
void produce() 
{
    while(1) 
	{
        cv::Mat img = cam.grab();
        mutex.lock();
        imageQueue.enqueue(img); // 存入图库
        condition.wakeOne();     // 唤醒等图的算法线程
        mutex.unlock();
    }
}

// 消费者线程(算法/存盘)
void consume() {
    while(1) {
        mutex.lock();
        while(imageQueue.isEmpty())
		{
			condition.wait(&mutex); // 没图,挂起消费者
		}
        cv::Mat img = imageQueue.dequeue();
        mutex.unlock();
        process(img); // 执行耗时算法
    }
}

4.主从模式

核心思想:分治与汇总。将一个大任务拆分成多个并行的小任务,由多个工人同时完成。

工作原理:

  1. Master 线程:负责任务的分发、监控和结果汇总。
  2. Worker 线程:负责执行具体的子任务逻辑。
  3. Master 将任务丢进任务池,Workers 竞争或按需领取任务。
cpp 复制代码
//拿到一张大图后,分发给多个线程同时检测不同区域(如OCR、划痕、尺寸)
void MasterProcess(cv::Mat fullImage) 
{
    // Master 负责拆解任务
    QList<cv::Rect> regions = {rect1, rect2, rect3};
    
    // 分发给多个 Worker 并行执行
    QtConcurrent::blockingMap(regions, [fullImage](const cv::Rect& r){
        cv::Mat subImg = fullImage(r);
        RunAlgorithm(subImg); // 多个核心同时跑不同的区域
    });
    
    // 所有 Worker 完成后,Master 汇总结果显示
    updateUI();
}

5.管道模式

核心思想:流水线并行。将任务拆分为有序的阶段,每个阶段由独立线程负责,提高整体吞吐量。

工作原理:

  1. 数据像流水一样经过 A -> B -> C 三个阶段。
  2. 当阶段 B 在处理第 N 个数据时,阶段 A 已经在处理第 N+1 个数据。
  3. 类似于 CPU 的指令流水线。
cpp 复制代码
#include <QQueue>
#include <QMutex>
#include <QWaitCondition>

template <typename T>
class SafeQueue 
{
    QQueue<T> queue;
    QMutex mutex;
    QWaitCondition condition;
    int maxSize = 5; // 限制大小,防止处理太慢导致内存爆炸

public:
    void push(T value) 
	{
        QMutexLocker locker(&mutex);
        if (queue.size() >= maxSize) 
		{
			queue.dequeue(); // 丢弃最旧的图(可选)
		}
        queue.enqueue(value);
        condition.wakeOne();
    }

    T pop() 
	{
        QMutexLocker locker(&mutex);
        while (queue.isEmpty()) 
		{
			condition.wait(&mutex); // 没数据就阻塞休眠
		}
        return queue.dequeue();
    }
};


//取像
void stageGrab(SafeQueue<cv::Mat>& outQueue) 
{
    while (true) 
	{
        cv::Mat frame = captureFromCamera(); // 模拟硬件取像
        outQueue.push(frame);
        QThread::msleep(30); // 模拟 33 FPS
    }
}

//预处理
void stagePreProcess(SafeQueue<cv::Mat>& inQueue, SafeQueue<cv::Mat>& outQueue) 
{
    while (true) 
	{
        cv::Mat frame = inQueue.pop(); // 阻塞等待 Stage A 的图
        
        // 执行耗时的图像操作
        cv::GaussianBlur(frame, frame, cv::Size(5, 5), 0);
        cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY);
        
        outQueue.push(frame); // 传给 Stage C
    }
}

//识别
void stageIdentify(SafeQueue<cv::Mat>& inQueue)
 {
    while (true) 
	{
        cv::Mat frame = inQueue.pop(); // 阻塞等待 Stage B 的图
        
        // 执行复杂的识别逻辑
        std::string result = doOCR(frame); 
        qDebug() << "识别结果:" << QString::fromStdString(result);
    }
}

// 1. 定义两个中转管道
SafeQueue<cv::Mat>* queueA = new SafeQueue<cv::Mat>();	//取像队列
SafeQueue<cv::Mat>* queueB = new SafeQueue<cv::Mat>();	//预处理后(识别)的图像队列

// 2. 启动所有工位(在不同线程运行)
QtConcurrent::run([=]() { stageGrab(*queueA); });					//取像
QtConcurrent::run([=]() { stagePreProcess(*queueA, *queueB); });	//预处理
QtConcurrent::run([=]() { stageIdentify(*queueB); });				//识别
相关推荐
h64648564h2 小时前
CANN 性能剖析与调优全指南:从 Profiling 到 Kernel 级优化
人工智能·深度学习
数据与后端架构提升之路2 小时前
论系统安全架构设计及其应用(基于AI大模型项目)
人工智能·安全·系统安全
忆~遂愿2 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
Liue612312313 小时前
YOLO11-C3k2-MBRConv3改进提升金属表面缺陷检测与分类性能_焊接裂纹气孔飞溅物焊接线识别
人工智能·分类·数据挖掘
一切尽在,你来3 小时前
第二章 预告内容
人工智能·langchain·ai编程
23遇见3 小时前
基于 CANN 框架的 AI 加速:ops-nn 仓库的关键技术解读
人工智能
Codebee3 小时前
OoderAgent 企业版 2.0 发布的意义:一次生态战略的全面升级
人工智能
光泽雨3 小时前
检测阈值 匹配阈值分析 金字塔
图像处理·人工智能·计算机视觉·机器视觉·smart3
Σίσυφος19004 小时前
PCL 法向量估计-PCA邻域点(经典 kNN 协方差)的协方差矩阵
人工智能·线性代数·矩阵
小鸡吃米…4 小时前
机器学习的商业化变现
人工智能·机器学习