C++并发之阻塞队列(block,queue)

news2024/11/15 9:14:26

目录

  • 1 概述
  • 2 实现
  • 3 测试
  • 3 运行

1 概述

  最近研究了C++11的并发编程的线程/互斥/锁/条件变量,利用互斥/锁/条件变量实现一个支持多线程并发的阻塞队列,队列大小没有限制。
阻塞队列是一个模板类,有两个模块参数,参数1是元素类型,参数2是容器类型,可以是std::deque和std::list,默认是std::deque。入队操作没有阻塞,出队操作如果队列为空则阻塞。
其类图为:
类图

2 实现

实现代码如下:

#ifndef BLOCK_QUEUE_H
#define BLOCK_QUEUE_H
#include <deque>
#include <mutex>
#include <condition_variable>

template<typename T, typename Sequence = std::deque<T>>
class block_queue
{
    Sequence                queue_;
    std::mutex              mutex_;
    std::condition_variable cv_;
public:
    typedef typename Sequence::value_type         value_type;
    typedef typename Sequence::size_type          size_type;
    typedef typename std::unique_lock<std::mutex> lock_type;
    block_queue() = default;
    block_queue(block_queue const&) = delete;
    block_queue(block_queue&& ) = delete;
    block_queue& operator = (block_queue const&) = delete;
    block_queue& operator = (block_queue &&) = delete;
   
    bool empty() const
    {
        lock_type lock(mutex_);
        return queue_.empty();
    }
    size_type size() const
    {
        lock_type lock(mutex_);
        return queue_.size();
    }

    void push(value_type const& value)
    {
        {
            lock_type lock(mutex_);
            queue_.push_back(value);
        }
        cv_.notify_one();
    }

    void push(value_type && value)
    {
        {
            lock_type lock(mutex_);
            queue_.push_back(std::move(value));
        }
        cv_.notify_one();
    }

    template<class... Args>
    void emplace(Args&&... args)
    {
        {
            lock_type lock(mutex_);
            queue_.emplace_back(args...);
        }
        cv_.notify_one();
    }

    value_type pop()
    {
        lock_type lock(mutex_);
        while(queue_.empty())
            cv_.wait(lock);

        value_type  value = std::move(queue_.front());
        queue_.pop_front();
        return value;
    }
};
#endif

说明:

  • 三个入队接口:
    • push(T const&) 左值入队
    • push(T &&) 左值入队
    • emplace() 构造参数入队
  • 一个出队接口
    • pop()

3 测试

基于cpptest的测试代码如下:

template<typename Sequence>
struct Function4BQ
{
    block_queue<std::string, Sequence> queue;
    std::mutex mutex;
    int counter = 0;
    void consume1(size_t n)
    {
        std::cerr << "\n";
        for(size_t i = 0; i < n; ++i)
        {
            std::cerr << "I get a " << queue.pop() << std::endl;
            counter++;
        }
    }
    void consume2(size_t id)
    {
        std::string fruit = queue.pop();
        {
            std::unique_lock<std::mutex> lock(mutex);
            std::cerr << "\nI get a " << fruit << " in thread(" << id << ")" << std::endl;
            counter++;
        }
    }
    void product1(std::vector<std::string> & fruits)
    {
        for(auto const& fruit: fruits)
            queue.emplace(fruit + std::string(" pie"));
    }
    void product2(std::vector<std::string> & fruits)
    {
        for(auto const& fruit: fruits)
            queue.push(fruit + std::string(" pie"));
    }
    void product3(std::vector<std::string> & fruits)
    {
        for(auto const& fruit: fruits)
            queue.push(fruit);
    }
};
typedef Function4BQ<std::deque<std::string>> Function4BqDeque;
typedef Function4BQ<std::list<std::string>>  Function4BqList;
void BlockQueueSuite::one_to_one()
{
    Function4BqDeque function;
    std::vector<std::string> fruits{"Apple", "Banana", "Pear", "Plum", "Pineapple"};
    std::thread threads[2];
    threads[0] = std::thread(&Function4BqDeque::product1, std::ref(function), std::ref(fruits));
    threads[1] = std::thread(&Function4BqDeque::consume1, std::ref(function), fruits.size());

    for(auto &thread : threads)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)
    
    function.counter = 0;
    threads[0] = std::thread(&Function4BqDeque::product2, std::ref(function), std::ref(fruits));
    threads[1] = std::thread(&Function4BqDeque::consume1, std::ref(function), fruits.size());

    for(auto &thread : threads)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)

    function.counter = 0;
    threads[0] = std::thread(&Function4BqDeque::product3, std::ref(function), std::ref(fruits));
    threads[1] = std::thread(&Function4BqDeque::consume1, std::ref(function), fruits.size());

    for(auto &thread : threads)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)

}

void BlockQueueSuite::one_to_multi()
{
    Function4BqList function;
    std::vector<std::string> fruits{"Apple", "Banana", "Pear", "Plum", "Pineapple"};
    std::thread product;
    std::vector<std::thread> consumes(fruits.size());
    
    for(size_t i = 0; i < consumes.size(); ++i)
        consumes[i] = std::thread(&Function4BqList::consume2, std::ref(function), i);
    product = std::thread(&Function4BqList::product1, std::ref(function), std::ref(fruits));
    
    product.join();
    for(auto &thread : consumes)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)

    function.counter = 0;
    for(size_t i = 0; i < consumes.size(); ++i)
        consumes[i] = std::thread(&Function4BqList::consume2, std::ref(function), i);
    product = std::thread(&Function4BqList::product2, std::ref(function), std::ref(fruits));
    product.join();
    for(auto &thread : consumes)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)

    function.counter = 0;
    for(size_t i = 0; i < consumes.size(); ++i)
        consumes[i] = std::thread(&Function4BqList::consume2, std::ref(function), i);
    product = std::thread(&Function4BqList::product3, std::ref(function), std::ref(fruits));
    product.join();
    for(auto &thread : consumes)
        thread.join();
    TEST_ASSERT_EQUALS(fruits.size(), function.counter)
}

说明:

  • 函数one_to_one测试一个生成者对应一个消费者(容器类型使用std::deque)。
  • 函数one_to_multi测试一个生产者对应多个消费者(容器类型使用std::list)

3 运行

BlockQueueSuite: 0/2
I get a Apple pie
I get a Banana pie
I get a Pear pie
I get a Plum pie
I get a Pineapple pie

I get a Apple pie
I get a Banana pie
I get a Pear pie
I get a Plum pie
I get a Pineapple pie

I get a Apple
I get a Banana
I get a Pear
I get a Plum
I get a Pineapple
BlockQueueSuite: 1/2
I get a Apple pie in thread(0)

I get a Banana pie in thread(1)

I get a Pear pie in thread(2)

I get a Plum pie in thread(3)

I get a Pineapple pie in thread(4)

I get a Apple pie in thread(0)

I get a Banana pie in thread(1)

I get a Pear pie in thread(2)

I get a Plum pie in thread(3)

I get a Pineapple pie in thread(4)

I get a Apple in thread(0)

I get a Banana in thread(1)

I get a Pear in thread(2)

I get a Plum in thread(4)

I get a Pineapple in thread(3)
BlockQueueSuite: 2/2, 100% correct in 0.009150 seconds
Total: 2 tests, 100% correct in 0.009150 seconds

分析:

  • 从结果看入队顺序和出队顺序是一致的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1861271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小红书营销:解锁企业增长新引擎,与小红书集成实现精准获客

在数字化营销的新时代&#xff0c;小红书以其独特的社区文化和精准的用户定位&#xff0c;成为了品牌和企业争相入驻的热门平台。今天将探讨如何通过小红书平台进行营销获客&#xff0c;并强调与企业集成的重要性&#xff0c;以实现更高效的品牌增长。 一、小红书营销的独特优…

API的优势及应用场景(淘宝API测试的详细步骤)

一、API的优势 API的出现为应用程序间的通信提供了一种新的方式&#xff0c;它有以下优势&#xff1a; 1、降低开发难度 开发者可以通过API访问其他应用程序的数据和功能&#xff0c;避免了重复开发&#xff0c;降低了开发难度。 2、提高开发效率 API提供了一种标准化的通…

JavaWeb系列十一: Web 开发会话技术(Cookie, Session)

韩sir Cookie技术Cookie简单示意图Cookie常用方法Cookie创建Cookie读取JSESSIONID读取指定Cookie Cookie修改Cookie生命周期Cookie的有效路径Cookie作业布置Cookie注意事项Cookie中文乱码问题 Session技术Session原理示意图Session常用方法Session底层机制Session生命周期Sessi…

山洪灾害无线预警广播系统解决方案

一、国家政策 2021年水利部印发了《全国山洪灾害防治项目实施方案&#xff08;2021-2023年&#xff09;》&#xff0c;提出“到2023年&#xff0c;山洪灾害防治体系进一步健全&#xff0c;监测预警能力进一步提升&#xff0c;努力补齐山洪灾害防治当前存在的明显短板”的建设目…

ArcGIS Desktop使用入门(四)——ArcMap软件闪退无法打开问题

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

【前端项目笔记】5 分类管理

分类管理 效果展示&#xff1a; 创建商品管理的子分支 git代码回顾 git branch 查看所有分支&#xff08;*代表当前所处分支&#xff09; git checkout -b goods_cate 新建分支goods_cate git push -u origin goods_cate 将当前分支保存到云端origin命名为goods_cate&#x…

CVPR24新作:教你网络“影分身术”,半小时生成专属数字人的GaussianAvatar

论文标题&#xff1a; GaussianAvatar: Towards Realistic Human Avatar Modeling from a Single Video via Animatable 3D Gaussians 论文作者&#xff1a; Liangxiao Hu, Hongwen Zhang, Yuxiang Zhang, Boyao Zhou, Boning Liu, Shengping Zhang, Liqiang Nie 项目地址&…

如何运用Midjourney探究新中式美学?

新中式美学最近真是越来越火了&#xff0c;把传统中式元素和现代设计结合起来&#xff0c;不仅看着舒服&#xff0c;还特别有文化韵味。 1. 研究和准备 首先&#xff0c;得先弄清楚什么是新中式美学。说白了&#xff0c;就是把传统中式元素和现代设计结合起来。你可以看看相关…

费控4.0全面解决方案从源头破解企业费用管理痛点

随着企业数字化变革的加速&#xff0c;费控报销正处于最具有发展潜力的细分赛道&#xff0c;且无疑是具有 “长坡厚雪”属性的投资标的。但回归企业管理视角&#xff0c;作为一个用于企业非生产性费用管理的管理工具&#xff0c;费控报销平台的评判标准只有两个&#xff1a;好不…

开通商家转账到零钱最简单直接的办法

想要一次性开通微信支付商家转账到零钱功能&#xff0c;您可以按照以下步骤进行操作&#xff1a; 首先&#xff0c;确保您的商户号主体是没有正在处罚中的公司。个体工商户目前暂不支持此功能。同时&#xff0c;仔细检查是否存在严重的违规处罚记录&#xff0c;如果只是轻微的风…

剪辑如何剪辑制作视频短视频剪辑学习怎么学,难吗?

工欲善其事必先利其器&#xff0c;有一个好的工具能让你的工作如鱼得水&#xff0c;果你想在短视频中制作精良的视频&#xff0c;你就考虑电脑制作软件了。果你想制作精良的视频&#xff0c;你就考虑电脑制作软件了。 如何找到剪辑软件了&#xff1f;你可以直接去软件的官方。你…

常见的排序算法【总结】

目录 排序的基本概念与分类排序的稳定性内排序与外排序简单排序冒泡排序时间复杂度&#xff1a; O ( n 2 ) O(n^2) O(n2) 简单选择排序排序原理&#xff1a;时间复杂度&#xff1a; O ( n 2 ) O(n^2) O(n2) 插入排序排序原理&#xff1a;时间复杂度&#xff1a; O ( n 2 ) O(n^…

MCP2515汽车CAN总线支持SPI接口的控制器芯片替代型号DPC15

器件概述 DPC15是一款独立CAN控制器&#xff0c;可简化需要与CAN总线连接的应用。可以完全替代兼容MCP2515 图 1-1 简要显示了 DPC15 的结构框图。该器件主要由三个部分组成&#xff1a; 1. CAN 模块&#xff0c;包括 CAN 协议引擎、验收滤波寄存 器、验收屏蔽寄存器、发送和接…

解锁最强比较工具Beyond_Compare十大功能及下载注册

Beyond Compare是一款功能强大的文件和文件夹比较工具&#xff0c;以下是其十大用法&#xff1a; 文件内容比较&#xff1a; Beyond Compare能够详细比较两个文件的内容&#xff0c;以绿色表示添加的内容&#xff0c;红色表示删除的内容&#xff0c;黄色表示修改的内容。 用户…

基线管理是什么

0、背景 作为数据开发人员&#xff0c;我们日常工作的一部分就是夜间值班。”夜间值班“对于没有实际工作经验的同学来说可能比较陌生。 所谓夜间值班&#xff0c;主要是为了保证数据可以在我们的对外承诺时间前产出。而由于日常生产任务依赖关系异常复杂&#xff0c;上游任务…

QT自定义信号和槽函数

在QT中最重要也是必须要掌握的机制&#xff0c;就是信号与槽机制&#xff0c;在MFC上也就是类型的机制就是消息与响应函数机制 在QT中我们不仅要学会如何使用信号与槽机制&#xff0c;还要会自定义信号与槽函数&#xff0c;要自定义的原因是系统提供的信号&#xff0c;在一些情…

PointCloudLib-滤波模块(Filtering)-直通滤波

使用直通过滤器过滤点云 在本教程中,我们将学习如何沿着 指定维度 – 即,切断位于 或 在给定用户范围之外。 代码 首先,创建一个文件,比方说,在你最喜欢的 编辑器,并将以下内容放入其中:passthrough.cpp #include <iostream> #include <pcl/point_types.h&g…

探究Qt5【元对象编译器,moc】的 设计原理和技术细节

Qt5是一个跨平台C框架&#xff0c;它有个突出的特点就是其元对象系统&#xff0c;该系统通过扩展C的能力&#xff0c;为事件处理提供了信号与槽机制、为对象内省提供了属性系统。为了支持这些特性&#xff0c;Qt引入了元对象编译器&#xff08;Meta-Object Compiler, MOC&#…

安达发|生产制造业怎么做好一体化生产计划排产?

在生产制造业中&#xff0c;一体化生产计划排产是确保生产效率和产品质量的关键。要实现这一目标&#xff0c;企业需要采用高级排产软件&#xff08;APS&#xff09;来优化生产流程。以下是如何利用APS软件做好一体化生产计划排产的详细步骤和建议&#xff1a; 1. 需求分析与数…