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

在C++中如何实现线程安全的队列

在这里插入图片描述

个人主页 : 个人主页
个人专栏 : 《数据结构》 《C语言》《C++》《Linux》《网络》 《redis学习笔记》

文章目录

  • 前言
  • 如何实现一个线程安全的队列思路
  • 应用场景
  • 代码实现
  • 总结


前言

在这里插入图片描述
在一次和豆包的模拟面试中,豆包问我:“在C++中,如何实现一个线程安全的队列呢?”


根据C++标准,STL容器的线程安全性遵循以下规则:

  • 只读操作是线程安全的:多个线程可以同时调用const 成员函数(如size, empty, at等)读取同一个容器,只要没有线程修改容器
  • 写操作需要独占访问:如果至少有一个线程在修改容器(如push_back, earse, operator[]等),其它线程必须通过同步机制,来保护对该容器的访问
  • 不同容器实例独立:不同线程操作不同的容器实例。

但如果多个线程同时修改同一个容器,或一个线程修改,另一个线程读取都是线程不安全的

在这里插入图片描述


如何实现一个线程安全的队列思路

实现步骤:

  1. 使用std::queue作为底层容器
  2. 使用std::mutex保护队列的访问
  3. 使用std::condition_variable协调线程,特别是在队列空时等待
  4. 在push时获取锁,添加元素后通知一个等待的线程
  5. 在pop时,使用while循环等待队列非空,处理虚假唤醒
  6. 提供tryPop和waitAndPop等不同方法,以适用不同场景
  7. 考虑异常安全,使用lock_guard或unique_lock管理锁的声明周期

在C++中实现线程安全队列的核心就在于通过同步机制保护共享数据的访问,并协调生产者和消费者线程操作


应用场景

  • 生产者-消费者模型:多个生产者线程向队列添加任务,消费者线程处理任务
  • 线程池任务队列:线程池使用线程安全的队列分发任务,支持异步返回值(std::future)
  • 事件驱动系统:管理异步事件,确保按顺序处理回调

代码实现

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

template <typename T>
class ThreadSafeQueue {
public:
    // 入队操作
    // 获取锁后添加元素,并通知一个等待线程
    void push(T value) {
        std::lock_guard<std::mutex> lock(_mtx);
        if(_finish)  
            return ;

        _data_queue.push(value);
        _cv.notify_one();
    };

    // 非阻塞出队
    // 立即尝试获取元素,若队列为空则返回失败
    bool tryPop(T& value) {
        std::lock_guard<std::mutex> lock(_mtx);
        if(_data_queue.empty() || _finish)
            return false;   // 队列为空 or 终止符为true
    
        value = _data_queue.front();
        _data_queue.pop();
        return true;
    };
    
    // 阻塞出队
    // 等待队列非空后获取元素,处理虚假唤醒
    void waitAndPop(T& value) {
        std::lock_guard<std::mutex> lock(_mtx);
        _cv.wait(lock, [this](){
            return !_data_queue.empty() || _finish;
        });

        if(finish)
            return ;
        value = _data_queue.front();
        _data_queue.pop();
        return ;
    };
        
    // 终止队列
    // 设置终止标志并唤醒所有线程
    void finish() {
        std::lock_guard<std::mutex> lock(_mtx);
        _finish = true;
        _cv.notify_all();
    };

    // 判断队列是否为空
    bool empty() const {
        std::lock_guard<std::mutex> lock(_mtx);
        return _data_queue.empty();
    };

    // 获取队列元素个数
    int size()  {
        std::lock_guard<std::mutex> lock(_mtx);
        return _data_queue.size();
    }
private:
    std::queue<T> _data_queue;       // 底层容器就是queue
    std::mutex _mtx;                 // 互斥锁
    std::condition_variable _cv;     // 信号量 
    bool _finish = false;            // 终止标志
};

在这里插入图片描述


总结

以上就是我总结的在C++中如何实现线程安全的队列

在这里插入图片描述

相关文章:

  • Qt:窗口
  • CAN总线通信协议学习2——数据链路层之帧格式
  • 【Linux】TCP协议
  • 名词解释:vllm,大模型量化;以及如何在vllm实现大模型量化
  • Vue 系列之:基础知识
  • Java-servlet(二)Java-servlet-Web环境搭建(上)IDEA,maven和tomcat工具下载(附Gitee直接下载)
  • 现今大语言模型性能(准确率)比较
  • 《论企业集成架构设计及应用》审题技巧 - 系统架构设计师
  • 在Ubuntu 22.04 LTS 上安装 MySQL两种方式:在线方式和离线方式
  • 基于Java的AI应用开发实战:从模型训练到服务部署
  • 中间件专栏之Redis篇——Redis的基本IO网络模型
  • 每日OJ_牛客_NC316体育课测验(二)_拓扑排序_C++_Java
  • Typora安装教程(附安装包)Typora下载
  • 小结:BGP 的自动聚合与手动聚合
  • ENSP配置AAA验证
  • 鸿蒙日期格式工具封装及使用
  • Hadoop第一课(配置linux系统)
  • 【软考-架构】1.3、磁盘-输入输出技术-总线
  • Pico 4 Enterprise(企业版)与Unity的交互-有线串流调试篇
  • Spring 源码硬核解析系列专题(十二):Spring Integration 的消息驱动源码解析
  • 太平人寿党委书记赵峰调任海南省政府党组成员
  • 财政部:4月份中央收入增长1.6%,今年以来首月实现正增长
  • 海南征集民生领域涉嫌垄断违法行为线索,包括行业协会等领域
  • 《歌手2025》能否“爆”下去?
  • 4月22城新房价格上涨:上海一二手房价环比均上涨,核心城市土地热带动市场热度提升
  • 新冠阳性率升高,专家:新冠变异株致病力没太多变化