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 pieI get a Apple pie
I get a Banana pie
I get a Pear pie
I get a Plum pie
I get a Pineapple pieI 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.mzph.cn/news/860423.shtml

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

相关文章

MySQL2(Mysql对数据的增删改 数据的备份和还原 单表查询 常用的聚合函数(⭐⭐))

目录 一、Mysql对数据的增删改 1. 增加数据&#xff08;INSERT语句&#xff09; 2. 修改数据&#xff08;UPDATE语句&#xff09; ​编辑 WHERE子句&#xff08;⭐&#xff09;&#xff1a; ​编辑 3. 删除数据&#xff08;DELETE语句&#xff09; 删除数据&#xff0…

轮播图的制作大全

例如该样式: 1.Vue的方法(可实现自动轮播和左右按钮和下方原点按钮轮播) <div id="app"><div class="a" ref="b" @mouseenter="MouseFun(c)" @mouseleave="MouseFun(d)">//1.图片显示盒子<div class=&qu…

2024最新算法:北极海鹦优化(Arctic puffin optimization,APO)算法求解23个函数,MATLAB代码

一、算法介绍 北极海鹦优化&#xff08;Arctic puffin optimization&#xff0c;APO&#xff09;算法是2024年提出一种智能优化算法。该算法模拟海鹦在空中飞行和水下觅食两个阶段的行为&#xff0c;旨在实现勘探与开发之间更好的平衡。该算法包括几个关键操作&#xff0c;包括…

CS-流量通讯特征修改-端口store证书流量通讯规则

免责声明:本文仅做技术交流与学习... 目录 1.修改默认端口&#xff1a; 2.去除store证书特征&#xff1a; 查看证书指纹&#xff1a; 生成证书指纹&#xff1a; 应用证书指纹&#xff1a; 3.去除流量通讯特征&#xff1a; 规则资源 http流量特征修改: https流量特征修改:…

DNF手游攻略:平民玩家角色打造保姆级攻略!云手机游戏辅助!

在《地下城与勇士》&#xff08;DNF&#xff09;手游中&#xff0c;角色的成长与装备的提升是每位玩家追求的目标。然而&#xff0c;对于不愿意投入大量金钱的平民玩家来说&#xff0c;如何在有限的资源下最大化提升角色战力是一项需要深思熟虑的挑战。本文将详细介绍平民玩家在…

鸿蒙开发网络管理:【@ohos.net.webSocket (WebSocket连接)】

WebSocket连接 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 使用WebSocket建立服务器与客户端的双向连接&#xff0c;需要先通过[createWebSocket]方法创建[WebSocket]对象&#xff0c;然后通…

接口测试代码和工具

通过python的requests给接口发送请求进行测试 #coding:utf-8 import requests class TestApi(): url_login "https://legend-sit.omodaglobal.com/api/auth/oauth2/token" url_topic_b "https://legend-sit.omodaglobal.com/api/community/topic_b/page?…

Vue71-嵌套(多级)路由

一、需求 二、开发步骤 2-1、编写路由组件 2-2、编写路由规则 2-3、编写路由标签<router-link>、<router-view> 三、小结

计算预卷积特征

当冻结卷积层和训练模型时&#xff0c;全连接层或dense层(vgg.classifier)的输入始终是相同的。为了更好地理解&#xff0c;让我们将卷积块(在示例中为vgg.features块)视为具有了已学习好的权重且在训练期间不会更改的函数。因此&#xff0c;计算卷积特征并保存下来将有助于我们…

阿里云云服务器、ACR镜像服务、容器化实战:搭建企业应用

一、容器化基础知识 华为云免费试用服务器&#xff1a;https://activity.huaweicloud.com/free_test/index.html 阿里云docker容器教程&#xff1a;https://edu.aliyun.com/course/3111900/lesson/341807097 查询ip地址&#xff1a;www.ip138.com 二、容器化搭建企业应用实战 2…

【已解决】Python报错:NameError: name ‘Image‘ is not defined

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《AI实战中的各种bug…

性能评测系列(PT-010):Spring Boot + MySQL,高并发insert

一、测试概述 测试场景 场景编号&#xff1a; PT-010场景描述&#xff1a; Java应用&#xff0c;MySQL单表写测试目的&#xff1a;指定规格、配置、环境下&#xff0c;Java应用数据库简单写场景负载能力评估。&#xff08;不含调优&#xff0c;所测结果未必是最优结果&#x…

软RAID

硬盘 连续空间 无法 扩容 lvm 非连续空间 可以动态扩容 raid 备份&#xff0c; 提高读写性能&#xff0c;不能扩容 raid 是磁盘的集合&#xff0c;按照排列组合的方法不 一&#xff0c;给 raid 去了不同的名字 raid0 raid1 raid5 raid10 什么是 RAID "RAID"…

构建实用的Flutter文件列表:从简到繁的完美演进

前言&#xff1a;为什么我们需要文件列表&#xff1f; 在现代科技发展迅速的时代&#xff0c;我们的电脑、手机、平板等设备里积累了大量的文件&#xff0c;这些文件可能是我们的照片、文档、音频、视频等等。然而&#xff0c;当文件数量增多时&#xff0c;我们如何快速地找到…

驾校预约管理系统

摘 要 随着驾驶技术的普及和交通安全意识的增强&#xff0c;越来越多的人选择参加驾校培训&#xff0c;以获取驾驶执照。然而&#xff0c;驾校管理面临着日益增长的学员数量和繁琐的预约管理工作。为了提高驾校的管理效率和服务质量&#xff0c;驾校预约管理系统成为了必不可少…

微信app支付没上架开通方法

对于许多商家来说&#xff0c;特别是那些经营游戏、商城等拥有自己APP的商家&#xff0c;接入微信支付无疑是一个重要的步骤&#xff0c;它能让用户更方便地进行支付操作&#xff0c;提升购物体验。然而&#xff0c;随着微信支付政策的调整&#xff0c;现在开通APP支付并不像以…

手机照片压缩到20k以内免费,这几款心动软件快收好!

在数字化时代&#xff0c;手机拍照已成为我们记录生活的重要方式之一。然而&#xff0c;高清的照片也意味着占用着越来越多的手机存储空间。如果你正在为手机内存告急而烦恼&#xff0c;那么这几款手机照片压缩神器或许能成为你的救星&#xff01;它们不仅可以将照片轻松压缩至…

【Linux】多线程的相关知识点

一、线程安全 1.1 可重入 VS 线程安全 1.1.1 概念 线程安全&#xff1a;多个线程并发执行同一段代码时&#xff0c;不会出现不同的结果。常见对全局变量或者静态变量进行操作&#xff0c;并且没有锁的保护的情况下&#xff0c;会出现问题。重入&#xff1a;同一个函数被不同…

vue3通过vue-video-player实现视频倍速、默认全屏、拖拽进度条等功能

效果图&#xff1a; 1、场景&#xff1a; js原生的video标签在不同浏览器及不同型号手机上都展示的不一样&#xff0c;一部分没有倍速&#xff0c;一部分没有全屏等功能&#xff0c;为了统一视频播放的交互功能&#xff0c;使用vue-video-player插件来完成&#xff0c;vue-vid…

轻松打造分班查询系统,这个工具助您一臂之力!

新学期伊始&#xff0c;老师们知道该如何快捷制作并发布分班查询系统吗&#xff1f;面对繁杂的学生名单和班级分配&#xff0c;无疑是一项巨大的麻烦。传统的纸质通知效率低下&#xff0c;容易出错&#xff0c;更别提在信息传递过程中可能出现的混乱和误解了。 现在有一个工具可…