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,一经查实,立即删除!

相关文章

C++ 左值右值 || std::move() || 浅拷贝,深拷贝 || 数据类型

数据类型&#xff1a; 作用&#xff1a;决定变量所占内存空间的字节大小&#xff0c;和布局方式基本数据类型&#xff1a; 算数类型&#xff1a; 整形&#xff08;bool / char……扩展集 / int / long……&#xff09;&& 浮点形&#xff08;float/double……&#xff…

java-包装类 2

### 8. 包装类的应用场景 #### 8.1 集合框架 包装类在Java集合框架中得到了广泛应用&#xff0c;因为集合只能存储对象而不能存储基本数据类型。 java import java.util.HashMap; public class CollectionExample { public static void main(String[] args) { …

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…

接受两个参数,并基于给定的概率(40%和60%)返回相应的参数值

function getRandomValue(param1, param2) {// 生成一个0到1之间的随机数const randomNum Math.random();// 定义40%和60%的概率const probability1 0.4; // param1的概率为40%const probability2 0.6; // param2的概率为60%// 根据概率返回相应的参数if (randomNum < pr…

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流量特征修改:…

PostgreSQL 日志管理与故障排查(十二)

1. 日志类型与配置 1.1 日志级别 PostgreSQL 提供多种日志级别&#xff0c;可根据需求配置详细程度。 ERROR&#xff1a;仅记录错误消息。WARNING&#xff1a;记录警告和错误消息。LOG&#xff1a;记录所有普通日志消息。DEBUG&#xff1a;记录详细的调试信息。 1.2 配置日…

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

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

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

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

c++ 常用的锁及用法介绍和示例

2024/6/21 14:20:10 在 C++ 中,常用的锁主要包括以下几种:std::mutex、std::recursive_mutex、std::timed_mutex 和 std::shared_mutex。这些锁可以帮助我们在多线程编程中保护共享数据,避免竞争条件。以下是每种锁的介绍及其用法示例: std::mutex std::mutex 是最基本的互…

初识仓颉语言

仓颉编程语言是一种面向全场景应用开发的通用编程语言&#xff0c;可以兼顾开发效率和运行性能&#xff0c;并提供良好的编程体验&#xff0c;主要具有如下特点&#xff1a; 语法简明高效&#xff1a;仓颉编程语言提供了一系列简明高效的语法&#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?…

Python polars学习-07 缺失值

背景 polars学习系列文章&#xff0c;第7篇 缺失值 该系列文章会分享到github&#xff0c;大家可以去下载jupyter文件&#xff0c;进行参考学习 仓库地址&#xff1a;https://github.com/DataShare-duo/polars_learn 小编运行环境 import sysprint(python 版本&#xff1a;…

快手商品详情的应用范围和请求示例笔记

应用范围&#xff1a; 快手商品详情的应用范围广泛&#xff0c;主要体现在以下几个方面&#xff1a; 用户购买决策支持&#xff1a; 用户通过查看快手商品详情页&#xff0c;可以获取商品的详细信息&#xff0c;如名称、价格、库存、产地、规格、材质、功能特点等。 商品详…

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…

2.中国菜刀使用详解(OWASP实战训练)

2.中国菜刀使用详解&#xff08;OWASP实战训练&#xff09;&#xff08;OWASP实战训练&#xff09; Webshell&#xff08;1&#xff09;shell2.php #eval 使用PHP函数&#xff0c;例如PHPinfo&#xff08;2&#xff09;Shell3.php #system 使用Linux系统命令&#xff0c;列如ls…

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

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