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

目录

  • 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

分析:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【芯片】MCU的分类

MCU又称单片微型计算机(Single Chip Microcomputer )或者单片机&#xff0c;是把中央处理器(Central Process Unit&#xff1b;CPU)的频率与规格做适当缩减&#xff0c;并将内存(memory)、计数器(Timer)、USB、A/D转换、UART、PLC、DMA等周边接口&#xff0c;甚至LCD驱动电路都…

MySQL报错Duplicate entry ‘0‘ for key ‘PRIMARY‘

报错现场 现象解释 因为你在插入时没有给 Customer.Id 赋值&#xff0c;MySQL 会倾向于赋值为 NULL。但是主键不能为 NULL&#xff0c;所以 MySQL 帮了你一个忙&#xff0c;将值转换为 0。这样&#xff0c;在第二次插入时就会出现冲突&#xff08;如果已经有一条记录为 0&…

第二证券:什么是破净股票?破净股票好还是不好?

一家公司手上掌握的财物包含实物财物、公司注册资金、未分配利润、各种公积金及品牌价值等等&#xff0c;一家公司的负债包含贷款、应付款、其他公司给的预付款等等。公司的总财物减去总负债后得到的净财物&#xff0c;再除以股票总数&#xff0c;就是公司的每股净财物&#xf…

【LM-Debugger】让研究人员与开发者能够深入洞察并干预模型的预测过程,开启了模型透明度和可解释性的一扇新门

背景 基于 Transformer 的语言模型 (LM) 是现代 NLP 模型的支柱&#xff0c;但其内部预测构建过程不透明。这对于不了解模型为何做出特定预测的最终用户以及希望调试或修复模型行为的开发人员来说都是个问题用于检查和干预基于转换器的语言模型的交互式工具项目地址&#xff1…

React的Redux的状态管理

步骤 1.创建新项目 npx create-react-app react-redux 2.安装配套工具 npm i reduxjs/toolkit react-redux 3.启动项目 npm run start 4.在src目录下创建store文件夹 5.在store文件夹下创建modules文件夹 6.在store文件夹里创建index.js文件 7.在counterStore.js文件…

【扩散模型(二)】IP-Adapter 从条件分支的视角,快速理解相关的可控生成研究

系列文章目录 【扩散模型&#xff08;一&#xff09;】中介绍了 Stable Diffusion 可以被理解为重建分支&#xff08;reconstruction branch&#xff09;和条件分支&#xff08;condition branch&#xff09;本文将从该视角快速理解 IP-Adapter 以及相关可控生成研究。 文章目…

Open3D 删除点云中重复的点

目录 一、算法原理1、重叠点2、主要函数二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、重叠点 原始点云克隆一份   构造重叠区域   合并点云获得重叠点 2、主要…

第二期书生·浦语大模型实战营优秀项目一览

书生浦语社区于 2023 年年底正式推出了书生浦语大模型实战营系列活动&#xff0c;至今已有两期五批次同学参加大模型学习、实战&#xff0c;线上课程累计学习超过 10 万人次。 实战营特设项目实践环节&#xff0c;提供 A100 算力支持&#xff0c;鼓励学员动手开发。第 2 期实战…

SolidWorks北京正版代理商亿达四方:官方授权SolidWorks中国代理

在北京这座融合了古老文明与现代科技的都市中&#xff0c;亿达四方作为SolidWorks官方认证的北京区域正版代理商&#xff0c;正引领着一场设计与制造领域的革新风潮。我们致力于为北京及周边地区的企业提供原汁原味的SolidWorks软件及全方位的增值服务&#xff0c;共同推进首都…

想要用tween实现相机的移动,three.js渲染的canvas画布上相机位置一点没动,如何解决??

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【Git】版本控制器的方式:SVN集中式版本控制工具和Git分布式版本控制工具

一、应用场景 二、版本控制器的方式 三、SVN 集中式版本控制工具 四、Git 分布式版本控制工具 五、Git工作流程 一、应用场景 Git 在开发过程中提供了多种应用场景&#xff0c;帮助开发团队高效地管理代码、协同工作&#xff0c;并保证代码质量。以下是一些具体应用场景和相应…

Springboot Mybatis 多数据源配置以及使用

在Spring Boot中配置MyBatis的多数据源是一个常见需求&#xff0c;尤其是在需要连接多个数据库时&#xff0c;下面是详细的步骤指南。 引入依赖 首先&#xff0c;在你的pom.xml文件中添加Spring Boot、MyBatis和数据库连接的相关依赖。例如&#xff0c;如果你使用的是MySQL数…

python基础篇(6):global关键字

使用 global关键字 可以在函数内部声明变量为全局变量 未使用global关键字的代码&#xff1a; # global关键字&#xff0c;在函数内声明变量为全局变量 num 200def test_a():print(f"test_a: {num}")def test_b():num 500print(f"test_b: {num}")test_…

基于java+springboot+vue实现的宠物商城网站(文末源码+Lw)273

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;商品信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

智慧校园-毕业管理系统总体概述

在当今教育信息化的浪潮中&#xff0c;智慧校园毕业管理系统脱颖而出&#xff0c;它作为一项综合性的数字平台&#xff0c;全面覆盖了从毕业资格审查到学位授予的每一个关键步骤&#xff0c;旨在通过智能化手段&#xff0c;为高校的毕业管理工作带来革命性的变革。毕业管理系统…

JAVAEE之网络原理_传输控制协议(TCP)的滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答机制

前言 在前面几节&#xff0c;我们讲解了TCP协议的基本概念、报文格式。还介绍了确认应答机制、超时重传、连接管理机制&#xff0c;在本节中 我们将会继续介绍TCP协议的其他机制。 一、滑动窗口机制&#xff08;效率机制&#xff09; 在前面的章节中我们讨论了确认应答策略&…

dbeaver数据库链接工具

1、下载dbeaver 一个绿色版一个安装版&#xff0c;官网开源版 2、安装 3、可以导入之前navicat的链接 导入 选择navicat 反编译密码的&#xff1a;https://tool.lu/coderunner navicat 版本15的密码解密&#xff1a;https://www.iatodo.com/navicatpw

阿里云+Halo个人博客搭建

前言 本文将介绍使用阿里云Halo搭建一个个人网站&#xff0c;过程极其简单&#xff0c;不需要什么计算机基础&#xff0c;操作电脑跟着步骤做就行。 在开始之前&#xff0c;还需要做一些前置准备 购买好服务器&#xff0c;本文使用阿里云&#xff0c;系统选择CentOS 7.6 64位…

高质量数据不够用,合成数据是打开 AGI 大门的金钥匙吗?

编者按&#xff1a; 人工智能技术的发展离不开高质量数据的支持。然而&#xff0c;现有可用的高质量数据资源已日渐接近枯竭边缘。如何解决训练数据短缺的问题&#xff0c;是当前人工智能领域亟待解决的一个较为棘手的问题。 本期文章探讨了一种经实践可行的解决方案 —— 合成…

如何从零开始搭建成功的谷歌外贸网站?

先选择一个适合外贸网站的建站平台&#xff0c;如WordPress或Shopify。这些平台提供丰富的主题和插件&#xff0c;可以帮助你快速搭建和定制网站。设计网站时&#xff0c;注重用户体验&#xff0c;确保导航清晰、页面加载快速、移动端友好。确保网站的SEO优化。从关键词研究开始…