C++实现生产者与消费者模式方式

 更新时间:2025年12月28日 09:24:44   作者:star-keke  
多线程工作池示例:创建固定数量的工作线程,通过条件变量竞争任务队列,确保任务均匀分发,任务队列读写操作由互斥锁保护,避免竞争,使用`notify_one()`唤醒空闲线程,`notify_all()`停止时唤醒所有线程退出,适用于CPU/IO密集型任务

多线程工作池

  • 创建workerCount个工作线程(示例中为 3 个),每个线程执行相同的workerLoop逻辑。
  • 线程通过condition_variable竞争任务队列中的任务,确保任务被均匀分发。

线程安全保障

  • 任务队列的读写仍通过std::mutex保护,避免多线程竞争导致的数据错乱。
  • cv.notify_one()每次唤醒一个线程处理任务,cv.notify_all()在停止时唤醒所有线程退出。

任务分发逻辑

  • 生产者(主线程)提交任务时,通过notify_one()唤醒空闲线程,避免线程忙等。
  • 多个工作线程同时消费任务,提升任务处理效率(尤其适合 CPU/IO 密集型任务)。
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <functional>
#include <chrono>
#include <thread>
#include <vector>

// 任务队列类型
using Task = std::function<void()>;

int main() {
    std::mutex mtx;
    std::condition_variable cv;
    std::queue<Task> taskQueue;
    bool stop = false; // 退出标志
    const size_t workerCount = 3; // 工作线程数量
    std::vector<std::thread> workers; // 工作线程列表

    // ========== 工作线程循环:多线程消费任务 ==========
    auto workerLoop = [&](int workerId) {
        while (true) {
            Task task;

            // 加锁,获取任务或检测退出信号
            {
                std::unique_lock<std::mutex> lock(mtx);
                
                // 等待条件:有任务 或 需要停止
                cv.wait(lock, [&]() {
                    return !taskQueue.empty() || stop;
                });

                // 若停止且任务队列为空,退出循环
                if (stop && taskQueue.empty()) {
                    std::cout << "[线程" << workerId << "] 退出工作循环..." << std::endl;
                    break;
                }

                // 取出队列头部任务(多线程竞争,确保线程安全)
                task = std::move(taskQueue.front());
                taskQueue.pop();
                std::cout << "[线程" << workerId << "] 取出任务,准备执行..." << std::endl;
            } // 解锁,避免执行任务时持有锁

            // 执行任务
            if (task) {
                task();
            }
        }
    };

    // ========== 创建多个工作线程 ==========
    for (int i = 0; i < workerCount; ++i) {
        workers.emplace_back(workerLoop, i);
    }

    // ========== 模拟提交任务(生产者逻辑) ==========
    auto submitTask = [&](Task task) {
        std::lock_guard<std::mutex> lock(mtx);
        taskQueue.push(std::move(task));
        std::cout << "提交任务,当前队列大小:" << taskQueue.size() << std::endl;
        cv.notify_one(); // 唤醒一个等待的工作线程
    };

    // 批量提交10个任务
    for (int i = 0; i < 10; ++i) {
        submitTask([i]() {
            std::cout << "执行任务" << i << ":线程ID=" << std::this_thread::get_id() << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 模拟任务耗时
        });
    }

    // 等待所有任务执行(可选,也可通过队列状态判断)
    std::this_thread::sleep_for(std::chrono::seconds(3));

    // ========== 停止所有工作线程 ==========
    {
        std::lock_guard<std::mutex> lock(mtx);
        stop = true;
        cv.notify_all(); // 唤醒所有等待的线程,确保全部退出
        std::cout << "\n通知所有线程停止..." << std::endl;
    }

    // 等待所有工作线程结束
    for (auto& worker : workers) {
        if (worker.joinable()) {
            worker.join();
        }
    }

    std::cout << "程序结束" << std::endl;
    return 0;
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • c语言分离三位数的实现

    c语言分离三位数的实现

    这篇文章主要介绍了c语言分离三位数的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • C语言软件spi虚拟总线中间层设计详解

    C语言软件spi虚拟总线中间层设计详解

    这篇文章主要为大家介绍了C语言软件spi虚拟总线中间层设计详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Qt使用QWT绘制柱状图详解

    Qt使用QWT绘制柱状图详解

    QT中提供了一个叫做QWT的库。QWT,全称是Qt Widgets for Technical Applications,是一个基于LGPL版权协议的开源项目,可生成各种统计图。本文将通过它绘制柱状图,需要的可以参考一下
    2022-01-01
  • C++虚函数到动态绑定的核心原理深入分析

    C++虚函数到动态绑定的核心原理深入分析

    这篇文章主要介绍了C++虚函数到动态绑定的核心原理,C++​​虚函数​​通过 ​虚函数表和​​虚指针实现动态绑定,使得基类指针引用在运行时能根据对象实际类型调用正确的函数版本,从而支持多态,需要的朋友可以参考下
    2025-05-05
  • C++ 整数拆分方法详解

    C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧
    2016-08-08
  • C++ DLL动态库的创建与调用(类库,隐式调用)

    C++ DLL动态库的创建与调用(类库,隐式调用)

    本文主要介绍了C++ DLL动态库的创建与调用(类库,隐式调用),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 深入解析C++中的引用类型

    深入解析C++中的引用类型

    引用指的是对一个对象的引用。那么什么是对象?在c++中狭义的对象指的是用类,结构,联合等复杂数据类型来声明的变量,如 MyClass myclass,CDialog mydlg,等等
    2013-09-09
  • C++访问std::variant类型数据的几种方式小结

    C++访问std::variant类型数据的几种方式小结

    std::variant是 C++17中引入的一个新的类模板,提供了一种存储不同类型的值的方式,本文主要介绍了C++访问std::variant类型数据的几种方式小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • 一文带你彻底搞定C++中文输出乱码的问题

    一文带你彻底搞定C++中文输出乱码的问题

    这篇文章主要为大家详细介绍了C++中文输出乱码的相关解决方法,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下
    2025-10-10
  • Visual Studio 2019创建C++ Hello World项目的方法

    Visual Studio 2019创建C++ Hello World项目的方法

    这篇文章主要介绍了Visual Studio 2019创建C++ Hello World项目的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论