【CPP】单生产者单消费者无锁队列使用记录

2024-08-25 01:28

本文主要是介绍【CPP】单生产者单消费者无锁队列使用记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

无锁队列地址:https://github.com/cameron314/readerwriterqueue

该仓库提供三种队列:

  • 无锁队列
  • 带阻塞与超时的无锁队列
  • 无锁环形缓存
    以下通过三个官方例子与简要说明进行阐述。

1. 无锁队列

1.1 打印输出函数

#include <readerwriterqueue.h>
#include <iostream>template <class T>
void PrintQueue(moodycamel::ReaderWriterQueue<T>& queue, const char* description = nullptr) {std::cout << "------------------------------------------------ " << std::endl;std::cout << "description  : " << description << std::endl;std::cout << "max_capacity : " << queue.max_capacity() << std::endl;std::cout << "size_approx  : " << queue.size_approx() << std::endl;std::cout << "peek address : " << queue.peek() << std::endl;T    element;bool succeeded;while (queue.size_approx() > 0) {succeeded = queue.try_dequeue(element);if (succeeded) {std::cout << element << " ";}}std::cout << std::endl;
}

1.2 查看基本信息

{// 默认构造moodycamel::ReaderWriterQueue<int> q;  // max_capacity: 15PrintQueue(q, "default");// 有参构造,查看最大容量moodycamel::ReaderWriterQueue<int> q3(3);  // max_capacity: 3PrintQueue(q3, "3");// 有参构造,查看最大容量moodycamel::ReaderWriterQueue<int> q5(5);  // max_capacity: 7PrintQueue(q5, "5");
}

输出:

------------------------------------------------ 
description  : default
max_capacity : 15
size_approx  : 0
peek address : 0------------------------------------------------ 
description  : 3
max_capacity : 3
size_approx  : 0
peek address : 0------------------------------------------------ 
description  : 5
max_capacity : 7
size_approx  : 0
peek address : 0

注意
如果给定的容量大小为2^n -1,则容量为指定值;否则,容量为大于给定值且最小的2^n-1

1.3 插入元素

1.3.1 enqueue/emplace

{moodycamel::ReaderWriterQueue<int> q(3);PrintQueue(q, "init");for (int index = 0; index < 5; index++) {// q.enqueue(index);q.emplace(index);}PrintQueue(q, "enqueue/emplace");  // 0 1 2 3 4 5 6 7
}

输出:

------------------------------------------------ 
description  : init
max_capacity : 3
size_approx  : 0
peek address : 0------------------------------------------------ 
description  : enqueue/emplace
max_capacity : 10
size_approx  : 5
peek address : 0x7e5ca0
0 1 2 3 4 

注意
函数enqueue/emplace在队列满后,会分配新的空间以存放插入元素。队列的容量会发生变化。这里仅验证了二次分配的规律:

指定大小容量大小二次分配容量大小
3310
5722
91546

二次分配的容量为首次分配容量的三倍减一,即3n-1

1.3.2 try_enqueue/try_emplace

{moodycamel::ReaderWriterQueue<int> q(5);for (int index = 0; index < 10; index++) {// q.try_emplace(index);if (!q.try_enqueue(index)) {std::cout << "Insert element is failed, element: " << index << std::endl;}}PrintQueue(q, "try_enqueue/try_emplace");  // 0 1 2 3 4 5 6
}

输出

Insert element is failed, element: 7
Insert element is failed, element: 8
Insert element is failed, element: 9
------------------------------------------------ 
description  : try_enqueue/try_emplace
max_capacity : 7
size_approx  : 7
peek address : 0x725ca0
0 1 2 3 4 5 6 

注意
函数try_enqueue/try_emplace在队列满时,不会分配新的空间以存储插入元素。插入元素被丢弃。

1.4 完整代码

#include <readerwriterqueue.h>#include <iostream>template <class T>
void PrintQueue(moodycamel::ReaderWriterQueue<T>& queue, const char* description = nullptr) {std::cout << "------------------------------------------------ " << std::endl;std::cout << "description  : " << description << std::endl;std::cout << "max_capacity : " << queue.max_capacity() << std::endl;std::cout << "size_approx  : " << queue.size_approx() << std::endl;std::cout << "peek address : " << queue.peek() << std::endl;T    element;bool succeeded;while (queue.size_approx() > 0) {succeeded = queue.try_dequeue(element);if (succeeded) {std::cout << element << " ";}}std::cout << std::endl;
}int main() {{// 默认构造moodycamel::ReaderWriterQueue<int> q;  // max_capacity: 15PrintQueue(q, "default");// 有参构造,查看最大容量moodycamel::ReaderWriterQueue<int> q3(3);  // max_capacity: 3PrintQueue(q3, "3");// 有参构造,查看最大容量moodycamel::ReaderWriterQueue<int> q5(5);  // max_capacity: 7PrintQueue(q5, "5");}{moodycamel::ReaderWriterQueue<int> q(5);for (int index = 0; index < 10; index++) {// q.try_emplace(index);if (!q.try_enqueue(index)) {std::cout << "Insert element is failed, element: " << index << std::endl;}}PrintQueue(q, "try_enqueue/try_emplace");  // 0 1 2 3 4 5 6}{moodycamel::ReaderWriterQueue<int> q(3);PrintQueue(q, "init");for (int index = 0; index < 5; index++) {// q.enqueue(index);q.emplace(index);}PrintQueue(q, "enqueue/emplace");  // 0 1 2 3 4 5 6 7}return EXIT_SUCCESS;
}

2. 带阻塞与超时的无锁队列

基本使用与无所队列相同,提供了额外的阻塞函数。

#include <readerwriterqueue.h>#include <iostream>template <class T>
void PrintQueue(moodycamel::BlockingReaderWriterQueue<T>& queue, const char* description = nullptr) {std::cout << "------------------------------------------------ " << std::endl;std::cout << "description  : " << description << std::endl;std::cout << "max_capacity : " << queue.max_capacity() << std::endl;std::cout << "size_approx  : " << queue.size_approx() << std::endl;std::cout << "peek address : " << queue.peek() << std::endl;T    element;bool succeeded;while (queue.size_approx() > 0) {succeeded = queue.try_dequeue(element);if (succeeded) {std::cout << element << " ";}}std::cout << std::endl;
}int main() {{moodycamel::BlockingReaderWriterQueue<int> q;  // max_capacity: 15PrintQueue(q, "default");moodycamel::BlockingReaderWriterQueue<int> q3(3);  // max_capacity: 3PrintQueue(q3, "3");moodycamel::BlockingReaderWriterQueue<int> q5(5);  // max_capacity: 7PrintQueue(q5, "5");}{moodycamel::BlockingReaderWriterQueue<int> q(5);for (int index = 0; index < 8; index++) {// q.enqueue(index);q.emplace(index);}PrintQueue(q, "enqueue/emplace");  // 0 1 2 3 4 5 6 7}{moodycamel::BlockingReaderWriterQueue<int> q(5);for (int index = 0; index < 8; index++) {// q.try_emplace(index);if (!q.try_enqueue(index)) {std::cout << "Insert element is failed, element: " << index << std::endl;}}PrintQueue(q, "try_enqueue/try_emplace");  // 0 1 2 3 4 5 6}{moodycamel::BlockingReaderWriterQueue<int> q(5);for (int index = 0; index < 8; index++) {q.emplace(index);}int element1;q.wait_dequeue(element1);  // 如果队列为空,函数会阻塞到队列非空int  element2;if (q.wait_dequeue_timed(element2, 5)) {  // 如果队列为空,函数会阻塞到超时结束,然后返回falsestd::cout << "element2: " << element2 << std::endl;}PrintQueue(q, "wait_dequeue/wait_dequeue_timed");}return EXIT_SUCCESS;
}

3. 无锁环形缓存

#include <readerwritercircularbuffer.h>#include <iostream>template <class T>
void PrintQueue(moodycamel::BlockingReaderWriterCircularBuffer<T>& queue, const char* description = nullptr) {std::cout << "------------------------------------------------ " << std::endl;std::cout << "description  : " << description << std::endl;std::cout << "max_capacity : " << queue.max_capacity() << std::endl;std::cout << "size_approx  : " << queue.size_approx() << std::endl;T    element;bool succeeded;while (queue.size_approx() > 0) {succeeded = queue.try_dequeue(element);if (succeeded) {std::cout << element << " ";}}std::cout << std::endl;
}int main() {{moodycamel::BlockingReaderWriterCircularBuffer<int> q3(3);  // max_capacity: 3PrintQueue(q3, "3");moodycamel::BlockingReaderWriterCircularBuffer<int> q5(5);  // max_capacity: 5PrintQueue(q5, "5");// 容量为指定位置}{moodycamel::BlockingReaderWriterCircularBuffer<int> q(5);for (int index = 0; index < 8; index++) {if (!q.try_enqueue(index)) {  // 如果插入元素时,队列已满,则丢弃std::cout << "Insert element is failed, element: " << index << std::endl;}}PrintQueue(q, "try_enqueue");  // 0 1 2 3 4}{moodycamel::BlockingReaderWriterCircularBuffer<int> q(5);for (int index = 0; index < 8; index++) {if (!q.wait_enqueue_timed(index, 5)) {  // 队列已满且在指定的超时时间内未获得存储空间,则插入失败,元素被丢弃std::cout << "Insert element is failed, element: " << index << std::endl;}}PrintQueue(q, "wait_enqueue_timed");  // 0 1 2 3 4}{moodycamel::BlockingReaderWriterCircularBuffer<int> q(5);for (int index = 0; index < 8; index++) {q.try_enqueue(index);}int element1;q.wait_dequeue(element1);std::cout << "wait_dequeue->element1: " << element1 << std::endl;int  element2;if (q.wait_dequeue_timed(element2, std::chrono::milliseconds(1))) {std::cout << "element2: " << element2 << std::endl;}PrintQueue(q, "wait_dequeue/wait_dequeue_timed");  // 2 3 4}return EXIT_SUCCESS;
}

这篇关于【CPP】单生产者单消费者无锁队列使用记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104162

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他