c++怎么实现一个阻塞队列_c++生产者消费者模型实现【多线程】


该文实现了基于C++标准库的线程安全阻塞队列模板类BlockingQueue,支持容量限制、阻塞入队/出队及超时尝试出队;配套生产者生成随机数、消费者取数处理,并通过多线程协同演示完整生产者-消费者模型。

c++怎么实现一个阻塞队列_c++生产者消费者模型实现【多线程】

(以下为纯 C++ 多线程阻塞队列 + 生产者消费者模型实现,基于标准库 <queue></queue><mutex></mutex><condition_variable></condition_variable><thread></thread>,无第三方依赖,可直接编译运行)

核心思路:用互斥锁保护共享队列,用条件变量让空队列时消费者等待、满队列时生产者等待。C++ 标准库的 std::condition_variable 天然支持“等待某个条件成立”,配合 wait()notify_one()/notify_all() 即可实现线程安全的阻塞行为。

1. 线程安全的阻塞队列模板类

支持任意类型 T,可设容量上限(可选),内部自动处理 wait/notify 逻辑:

#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>

template<typename T>
class BlockingQueue {
private:
    std::queue<T> q;
    mutable std::mutex mtx;
    std::condition_variable not_empty;   // 消费者等待:队列非空
    std::condition_variable not_full;    // 生产者等待:队列未满(若限容)
    size_t max_size = 0;                 // 0 表示无容量限制

public:
    explicit BlockingQueue(size_t capacity = 0) : max_size(capacity) {}

    // 入队(阻塞直到有空间)
    void push(const T& item) {
        std::unique_lock<std::mutex> lock(mtx);
        if (max_size > 0) {
            not_full.wait(lock, [this] { return q.size() < max_size; });
        }
        q.push(item);
        not_empty.notify_one(); // 唤醒一个等待消费的线程
    }

    // 出队(阻塞直到有数据)
    T pop() {
        std::unique_lock<std::mutex> lock(mtx);
        not_empty.wait(lock, [this] { return !q.empty(); });
        T front = std::move(q.front());
        q.pop();
        if (max_size > 0) {
            not_full.notify_one(); // 可能腾出空间,唤醒一个等待生产的线程
        }
        return front;
    }

    // 尝试出队(带超时,返回 false 表示超时或为空)
    bool try_pop(T& item, int timeout_ms = 0) {
        std::unique_lock<std::mutex> lock(mtx);
        if (timeout_ms == 0) {
            not_empty.wait(lock, [this] { return !q.empty(); });
        } else {
            auto dur = std::chrono::milliseconds(timeout_ms);
            if (!not_empty.wait_for(lock, dur, [this] { return !q.empty(); })) {
                return false;
            }
        }
        item = std::move(q.front());
        q.pop();
        if (max_size > 0) not_full.notify_one();
        return true;
    }

    size_t size() const {
        std::lock_guard<std::mutex> lock(mtx);
        return q.size();
    }

    bool empty() const {
        std::lock_guard<std::mutex> lock(mtx);
        return q.empty();
    }
};

2. 生产者与消费者函数(分离职责)

每个生产者/消费者都是独立函数,通过引用使用同一个队列,适合传给 std::thread

Prisma Prisma

Prisma是一款照片编辑工具,用户可以轻松地将照片转换成数字艺术。

Prisma 92 查看详情 Prisma

立即学习“C++免费学习笔记(深入)”;

#include <iostream>
#include <thread>
#include <vector>
#include <random>

// 生产者:生成随机数并入队
void producer(BlockingQueue<int>& bq, int id, int count) {
    std::mt19937 gen(id);
    std::uniform_int_distribution<int> dist(1, 100);
    for (int i = 0; i < count; ++i) {
        int val = dist(gen);
        bq.push(val);
        std::cout << "[P" << id << "] pushed " << val << "\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

// 消费者:取数、打印、简单处理
void consumer(BlockingQueue<int>& bq, int id, int total) {
    for (int i = 0; i < total; ++i) {
        int val = bq.pop(); // 阻塞等待
        std::cout << "  [C" << id << "] popped " << val << "\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(150));
    }
}

3. 主函数:启动多线程并协同运行

注意:需确保生产总数 ≥ 消费总数,否则消费者会永久阻塞(实际项目中建议加退出信号或使用 `try_pop` + 超时 + 中断机制):

int main() {
    BlockingQueue<int> bq(10); // 容量为 10 的有界队列

    const int num_producers = 2;
    const int num_consumers = 3;
    const int items_per_producer = 5;

    std::vector<std::thread> threads;

    // 启动生产者
    for (int i = 0; i < num_producers; ++i) {
        threads.emplace_back(producer, std::ref(bq), i, items_per_producer);
    }

    // 启动消费者(总消费数 = 总生产数)
    int total_items = num_producers * items_per_producer;
    for (int i = 0; i < num_consumers; ++i) {
        int each = total_items / num_consumers;
        int rest = (i == 0) ? total_items % num_consumers : 0;
        threads.emplace_back(consumer, std::ref(bq), i, each + rest);
    }

    // 等待所有线程结束
    for (auto& t : threads) {
        if (t.joinable()) t.join();
    }

    std::cout << "All done.\n";
    return 0;
}

4. 关键细节提醒

  • 始终用 std::unique_lock 配合 wait:它允许在等待期间临时释放锁,并在唤醒后自动重新加锁;普通 lock_guard 不支持
  • 条件检查必须用 lambda(谓词重载):避免虚假唤醒(spurious wakeup),不要只用 wait(lock) 后手动判断
  • notify_one() 通常够用:除非多个线程等待同一条件且需全部响应(如广播终止信号),否则用 notify_one() 更高效
  • 移动语义优化:pop 中用 std::move(q.front()) 避免不必要的拷贝(尤其对大对象)
  • 异常安全:所有 RAII 锁(unique_lock / lock_guard)保证异常时自动解锁

基本上就这些。不复杂但容易忽略条件变量的谓词写法和锁的搭配——写对了,就是教科书级的线程安全阻塞队列。

以上就是c++++怎么实现一个阻塞队列_c++生产者消费者模型实现【多线程】的详细内容,更多请关注其它相关文章!


# 并在  # 广州网站建设天维  # 烟草建设网站  # 商南短视频seo地址  # 顺德家政网站建设  # 网站推广渠道运营方案  # 武侯区网站推广建设优化  # 庆阳网站建设及推广  # 网站下线推广  # 零售怎么抖音推广优化营销  # 成安优化seo  # 中文网  # 相关文章  # ai  # 多个  # 边缘  # 都是  # 游戏开发  # 如何实现  # 随机数  # 多线程  # 标准库  # stream  # ios  # c++ 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: Flexbox布局:实现粘性导航与底部页脚的完美结合  Golang如何测试结构体方法_Golang reflect方法测试与调用技巧  百度网盘如何设置上传限额  PHP魔术方法__set与__isset:设计考量、性能权衡与静态分析的视角  《杖剑传说》食谱大全  中大网校app做题记录清除方法  济南公交卡手机充值指南  Coolpad5890 ROM刷机包  Vue 3中独立响应式实例的创建与应用  小红书网页版在线直达 小红书网页版免费登录入口  AO3中文入口稳定分享_AO3官网HTTPS看文详解  《蓝色星原:旅谣》坐骑获取攻略  漫蛙官网(首页入口)_漫蛙漫画稳定访问教程分享  冬季去哪个城市旅游更有可能观测到极光  荣耀盒子应用管理技巧  《广发易淘金》国债逆回购操作教程  LINUX怎么查看显卡信息_LINUX查看GPU状态  《磁力猫》最好用的磁官网  酷狗音乐多音轨设置教程  CSS过渡与滚动滚动事件结合应用_scroll与transition动画  怎样设置开机后自动运行某个程序_Windows启动文件夹与任务计划【自动化】  《小黑盒》删除历史浏览方法  电脑开不了机怎么办 电脑无法开机的解决方法  J*aScript模拟悬停与点击:自动化网页动态元素交互指南  OPPO A3 WiFi频繁断开怎么办 OPPO A3网络优化技巧  AffinityDesigner图层蒙版怎么用_AffinityDesigner图层蒙版设计应用  Final Cut Pro视频加EQ教程  Go语言中方法与接收器:指针和值类型的调用机制详解  《友玩*》创建群聊方法  Dash应用中自定义HTML页面标题与网站图标(F*icon)的实用指南  2025SNH48年度青春盛典门票价格及购买方式  荣耀Magic6 Pro拍照成像偏暗_荣耀Magic6 Pro夜景优化  J*a中逻辑运算符如何使用_逻辑与或非的基础用法讲解  vivo浏览器怎么离线保存网页 vivo浏览器下载完整页面以便无网络时阅读  视频转蓝光m2ts格式  126邮箱网页在线登录2025_126邮箱网页版入口官方地址  空腹吃苹果好吗 苹果空腹摄入指南  汽水音乐官网网页版入口 汽水音乐官网网页版在线入口  oppo手机如何通过下拉通知栏截图_oppo手机通知栏快捷截图方法  批改网网页版登录 批改网电脑版学生登录入口  cad视图选项卡不见了怎么办_cad视图标签恢复显示方法  ExcelSCAN与LAMBDA如何创建自定义移动平均函数_SCAN实现任意窗口期移动平均计算  深入理解Python对象引用与链表属性赋值  如何在mysql中比较InnoDB和MyISAM区别  百度输入法在AutoCAD中无法输入中文怎么办_百度输入法CAD输入异常解决方法  《腾讯相册管家》注销账号方法  风车动漫官网首页入口登录 风车动漫在线观看正版地址  Linux如何优化系统启动流程_Linux启动项优化方案  热血江湖归来医师加点攻略  如何解决Casbin日志与应用日志不统一的问题,使用casbin/psr3-bridge实现无缝集成 

 2025-12-20

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.