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

使用C++构建安全队列

1 背景

  • STL的容器不是线程安全的,我们经常会有需求要求数据结构线程安全,比如写生产者消费者模型的时候,就要求队列线程安全。
  • 利用std::queue和C++线程标准库的一些组件(mutex,condition_variable),可以写一个线程安全的队列ConcurrenceQueue。

2 思路梳理

需要4个函数

  • push,入队;
  • pop,出队并返回原来对头的元素,如果为队空则阻塞
  • tryPop,出队并返回原来对头的元素,如果队空返回空(使用智能指针作返回类型),非阻塞
  • empty,返回是否为空,实则没啥用,多线程条件下判空,下一瞬间另一线程就可能push进去东西了。

3 实现代码

#ifndef __CONCURRENCEQUEUE_H__
#define __CONCURRENCEQUEUE_H__
#include <mutex>
#include <condition_variable>
#include <deque>
#include <queue>
#include <memory>template<typename DATATYPE, typename SEQUENCE = std::deque<DATATYPE>>
class ConcurrenceQueue 
{
public:ConcurrenceQueue() = default;ConcurrenceQueue(const ConcurrenceQueue & other){std::lock_guard<std::mutex> lg(other.m_mutex);m_data = other.m_data;}ConcurrenceQueue(ConcurrenceQueue &&) = delete;ConcurrenceQueue & operator= (const ConcurrenceQueue &) = delete;~ConcurrenceQueue() = default;bool empty() const {std::lock_guard<std::mutex> lg(m_mutex);return m_data.empty();}void push(const DATATYPE & data) {std::lock_guard<std::mutex> lg(m_mutex);m_data.push(data);m_cond.notify_one();}void push(DATATYPE && data) {std::lock_guard<std::mutex> lg(m_mutex);m_data.push(std::move(data));m_cond.notify_one();}std::shared_ptr<DATATYPE> tryPop() {  // 非阻塞std::lock_guard<std::mutex> lg(m_mutex);if (m_data.empty()) return {};auto res = std::make_shared<DATATYPE>(m_data.front());m_data.pop();return res;}std::shared_ptr<DATATYPE> pop() {  // 非阻塞std::unique_lock<std::mutex> lg(m_mutex);m_cond.wait(lg, [this] { return !m_data.empty(); });auto res = std::make_shared<DATATYPE>(std::move(m_data.front()));m_data.pop();return res;}private:std::queue<DATATYPE, SEQUENCE> m_data;mutable std::mutex m_mutex;std::condition_variable m_cond;
};
#endif

 4 测试

全局的:

ConcurrenceQueue<int> g_queue;void producer() 
{    for (int i = 0; i < 100; ++i) {g_queue.push(i);std::this_thread::sleep_for(std::chrono::seconds(3));}
}void consumer1() 
{while (1) {std::printf("[1]  -------   %d\n", *g_queue.pop());}
}void consumer2() 
{while (1) {auto front = g_queue.tryPop();std::printf("[2]  -------   %d\n", front ? *front : -1);std::this_thread::sleep_for(std::chrono::seconds(1));}
}

测试 1:(消费者阻塞式消费)

int main () 
{std::thread t1(producer);std::thread t2(consumer1);t1.join();t2.join();return 0;
}

测试 2:(消费者非阻塞式消费,但要sleep轮询)

int main () 
{std::thread t1(producer);std::thread t2(consumer2);t1.join();t2.join();return 0;
}

http://www.lryc.cn/news/214541.html

相关文章:

  • EasyFlash移植使用- 关于单片机 BootLoader和APP均使用的情况
  • python捕获异常和scapy模块的利用
  • CSS+Javascript+Html日历控件
  • 让企业的数据用起来,数据中台=数据治理?
  • 【人工智能Ⅰ】5-粒子群算法
  • 软考高项-49个项目管理过程输入、输出和工具技术表
  • 《C和指针》(7)函数
  • vue3中的Props
  • ElasticSearch搜索技术深入与聚合查询实战
  • vue+element ui中的el-button自定义icon图标
  • PyQt5:构建目标检测算法GUI界面 (附python代码)
  • SV-10A-4G IP网络报警非可视终端 (4G版)
  • 对xml文本元素赋值
  • 【k8s】资源管理命令-陈述式
  • 无需频繁登录支付宝网站即可完成商家转账,实时到账,方便安全快捷
  • Vue 监听属性 watchEffect
  • 设计模式: 关于项目架构,技术选型,技术债务问题与解决方案
  • el-tabs 默认选中第一个
  • R -- match,pmatch,charmatch
  • 数据结构——线性表①(顺序表)
  • MFC网络编程-Udp客户端
  • 密码学基础
  • [Docker]四.Docker部署nodejs项目,部署Mysql,部署Redis,部署Mongodb
  • 拥抱AI-ChatGPT:人类新纪元
  • 基于深度学习的人脸表情识别 计算机竞赛
  • GitHub经常打不开或者访问解决办法
  • 密码学 - SHA-2
  • Vins-Fusion、Vins-Mono(之前那个编译通过但是没有这个好用)
  • 每日自动化提交git
  • 【Linux进程】再谈软件—操作系统(Operator System)