当前位置: 首页 > news >正文

spdlog生产者消费者模式

spdlog生产者消费者模式

spdlog提供了异步模式,显示的创建async_logger, 配合环形队列实现的消息队列和线程池实现了异步模式。异步logger提交日志信息和自身指针, 任务线程从消息队列中取出消息后执行对应的sink和flush动作。

1. 环形队列

1.1 环形队列基础

环形队列是一种首尾相连的队列,符合先进先出的逻辑。相比于普通队列而言,能够复用内存。通常被使用在任务调度、消费队列等场景中。spdlog中的环形队列用于异步模式下存储日志,线程池中的消费者线程不断的读取队列消息进行落日志。
环形队列
环形队列使用两个头尾指针表示实际数据的起点和终点。

  • 出队列
    出队列时,head指针向前移动即可,并不会对head位置的元素进行删除操作,
  • 队列满
    当tail + 1 == head时,认为是满队列。
  • 入队列
    tail指针向前移动,当队列满时新数据会覆盖之前的老数据,这时head指针也要向前移动。
  • 队列长度
    实际队列长度size = tail - head, 也存在一种情况,head位置大于tail位置(已经出现过满队列),此时size= max_element - (head - tail)

1.2 spdlog的环形队列实现

spdlog 在details/circular_q.h 中实现了环形队列模板类。

  • 使用了数据来模拟队列,提供按照元素下标访问的能力
  • 实现了移动拷贝
  • circular_q 多了一个属性 overrun_counter_记录因满队列丢弃的元素数
  • max_items_ 比实际长度大1,是为了便于判断队列满状态
template <typename T>
class circular_q {size_t max_items_ = 0;typename std::vector<T>::size_type head_ = 0;typename std::vector<T>::size_type tail_ = 0;size_t overrun_counter_ = 0;std::vector<T> v_;public:using value_type = T;// empty ctor - create a disabled queue with no elements allocated at allcircular_q() = default;explicit circular_q(size_t max_items): max_items_(max_items + 1)  // one item is reserved as marker for full q,v_(max_items_) {}circular_q(const circular_q &) = default;circular_q &operator=(const circular_q &) = default;// move cannot be default,// since we need to reset head_, tail_, etc to zero in the moved objectcircular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); }circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT {copy_moveable(std::move(other));return *this;}// push back, overrun (oldest) item if no room leftvoid push_back(T &&item) {if (max_items_ > 0) {v_[tail_] = std::move(item);tail_ = (tail_ + 1) % max_items_;if (tail_ == head_)  // overrun last item if full{head_ = (head_ + 1) % max_items_;++overrun_counter_;}}}// Return reference to the front item.// If there are no elements in the container, the behavior is undefined.const T &front() const { return v_[head_]; }T &front() { return v_[head_]; }// Return number of elements actually storedsize_t size() const {if (tail_ >= head_) {return tail_ - head_;} else {return max_items_ - (head_ - tail_);}}// Return const reference to item by index.// If index is out of range 0…size()-1, the behavior is undefined.const T &at(size_t i) const {assert(i < size());return v_[(head_ + i) % max_items_];}// Pop item from front.// If there are no elements in the container, the behavior is undefined.void pop_front() { head_ = (head_ + 1) % max_items_; }bool empty() const { return tail_ == head_; }bool full() const {// head is ahead of the tail by 1if (max_items_ > 0) {return ((tail_ + 1) % max_items_) == head_;}return false;}size_t overrun_counter() const { return overrun_counter_; }void reset_overrun_counter() { overrun_counter_ = 0; }private:// copy from other&& and reset it to disabled statevoid copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT {max_items_ = other.max_items_;head_ = other.head_;tail_ = other.tail_;overrun_counter_ = other.overrun_counter_;v_ = std::move(other.v_);// put &&other in disabled, but valid stateother.max_items_ = 0;other.head_ = other.tail_ = 0;other.overrun_counter_ = 0;}
};

2. 生产者消费者模式

生产者负责往环形队列中写入, 消费者负责从队列中取出数据,进行消费。可以看到,存在一个共享数据,也就是队列,所以需要一个锁来控制并发的读写;同时由于队列是有大小限制的,存在两个临界状态,也即队列空和队列满,所以需要两个条件变量,入队列的时候需要等待队列非满, 出队列的时候需要等待队列非空。

2.1 消息队列

spdlog在 details/mpmc_blocking_q.h中实现了消息队列。
入队列是提供了两种模式,阻塞和非阻塞方式,非阻塞情况下,会直接往环形队列中写入数据,在队列满时会导致数据被覆盖。
入队列
同样出队列,也提供了两种阻塞和非阻塞两种模式。
出队列

2.2 生产者消费者线程池

在异步模式下,存在一个全局的线程池。

// set global thread pool.
inline void init_thread_pool(size_t q_size,size_t thread_count,std::function<void()> on_thread_start,std::function<void()> on_thread_stop) {auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,on_thread_stop);details::registry::instance().set_tp(std::move(tp));
}

线程池中的线程会一直从环形队列中阻塞模式取出数据,执行对应的sink动作、flush动作、终止。
阻塞取数据
而async_logger 则是通过sink_it_往队列中写入数据。
生产者

异步模式

相关文章:

spdlog生产者消费者模式

spdlog生产者消费者模式 spdlog提供了异步模式&#xff0c;显示的创建async_logger, 配合环形队列实现的消息队列和线程池实现了异步模式。异步logger提交日志信息和自身指针&#xff0c; 任务线程从消息队列中取出消息后执行对应的sink和flush动作。 1. 环形队列 1.1 环形队…...

日语 13 14

13. スピーチの依頼 いらい 自信 自信 自信 自信 自信 じしん 折り入って 折り入って 折り入って おりいって  诚恳 頼み 頼み 頼み 頼み 頼み  たのみ 请求 整備 整備 整備 整備 整備 せいび 维修 肥満 肥満 肥満 肥満 肥満 ひまん 肥胖 権利 …...

初学者应该掌握的MySQL数据库的基本组成部分及概念

MySQL数据库作为一种开源的关系型数据库管理系统&#xff0c;被广泛应用于Web应用开发和数据存储。它具有高性能、易用性和可靠性等特点&#xff0c;是开发者们的首选之一。在本篇文章中&#xff0c;我们将详细介绍MySQL数据库的核心组成部分&#xff0c;帮助你深入理解这个强大…...

四川汇聚荣科技有限公司怎么样?

在探讨一家科技公司的综合实力时&#xff0c;我们往往从多个维度进行考量&#xff0c;包括但不限于公司的发展历程、产品与服务的质量、市场表现、技术创新能力以及企业文化。四川汇聚荣科技有限公司作为一家位于中国西部的科技企业&#xff0c;其表现和影响力自然也受到业界和…...

数据仓库和数据库有什么区别?

一、什么是数据仓库二、什么是数据库三、数据仓库和数据库有什么区别 一、什么是数据仓库 数据仓库&#xff08;Data Warehouse&#xff09;是一种专门用于存储和管理大量结构化数据的信息系统。它通过整合来自不同来源的数据&#xff0c;为企业提供统一、一致的数据视图&…...

计算子网掩码

例题 如果子网掩码是255.255.192.0&#xff0c; 那么下面主机&#xff08;&#xff09;必须通过路由器才能与主机129.23.144.16通信&#xff08; 1分 &#xff09;A.129.23.148.127B. 129.23.191.21C. 129.23.127.222D. 129.23.130.33计算 要确定哪些主机必须通过路由器才能与…...

JVM 垃圾收集算法

首先我们要知晓&#xff0c;垃圾收集是建立在两个分代假说之上的&#xff1a; ①弱分代假说&#xff1a;绝大多数对象都是朝生夕灭的 ②强分代假说&#xff1a;熬过越多次垃圾收集的对象就越难消亡 收集器应该将Java堆划分出不同的区域&#xff0c;然后将回收对象依据其年龄分配…...

安装虚拟环境

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Flask依赖两个外部库&#xff1a;Werkzeug和Jinja2。Werkzeug是一个WSGI&#xff08;在Web应用和多种服务器之间的标准 Python 接口&#xff09;工具…...

【ai】tx2-nx:安装深度学习环境及4.6对应pytorch

参考:https://www.waveshare.net/wiki/Jetson_TX2_NX#AI.E5.85.A5.E9.97.A8 英伟达2021年发布的的tritionserver 2.17 版本中,backend 有tensorflow1 和 onnxruntime ,他们都是做什么用的,作为backend 对于 triton 推理server意义是什么,是否应该有pytorch? Triton Infer…...

华为某员工爆料:三年前985本科起薪30万,现在硕士起薪还是30w,感慨互联网行情变化

“曾经的30万年薪&#xff0c;是985本科学历的‘标配’&#xff0c;如今硕士也只值这个价&#xff1f;” 一位华为员工的爆料&#xff0c;揭开了互联网行业薪资变化的冰山一角&#xff0c;也引发了不少人的焦虑&#xff1a;互联网人才“通货膨胀”的时代&#xff0c;真的结束了…...

Java基础--AOP--1.概述

一、AOP简介 AOP&#xff08;Aspect Oriented &#xff09;即为面向切面编程&#xff0c;也可称为面向方法编程&#xff0c;是方法增强的一种途径&#xff0c;通常可用于记录操作日志、权限空值、事务管理等等;Spring框架中的事务底层就是AOP。 二、AOP的组成 1、连接点&…...

【计算机网络仿真实验-实验3.1、3.2】交换路由综合实验

实验3.1 交换路由综合实验——作业1 一、实验目的 运用实验二&#xff08;可前往博主首页计算机网络专栏下查看&#xff09;中学到的知识&#xff0c;将这个图中的PC机连接起来组网并分析&#xff0c;本篇涉及代码以截图展示&#xff0c;过于简单的代码及操作不再详细介绍&…...

RSA密码系统的特定密钥泄露攻击与Coppersmith方法的应用

PrimiHub一款由密码学专家团队打造的开源隐私计算平台&#xff0c;专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 RSA密码系统作为当前最广泛使用的公钥加密算法之一&#xff0c;其安全性依赖于大整数分解问题的困难性。然而&#xff0c;随着计…...

从零开始精通Onvif之音视频流传输

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 概述 Onvif协议的核心作用之一&#xff0c;是定义了如何通过网络访问和控制IP摄像机和其他视频设备。Onvif协议不仅涉及设备发现、设备管理&…...

CentOS 7、Debian、Ubuntu,这些是什么意思

CentOS 7、Debian、Ubuntu 都是基于 Linux 内核的操作系统&#xff0c;它们各自有不同的特性和用途。以下是对它们的详细解释&#xff1a; CentOS 7 CentOS&#xff08;Community ENTerprise Operating System&#xff09; 是一个基于开源的 Linux 发行版。CentOS 7 是 CentOS …...

安装Flask

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 大多数Python包都使用pip实用工具安装&#xff0c;使用Virtualenv创建虚拟环境时会自动安装pip。激活虚拟环境后&#xff0c;pip 所在的路径会被添加…...

OSPF开销、协议优先级、定时器(华为)

#交换设备 OSPF开销值 如果没有定义OSPF接口的开销值&#xff0c;OSPF会根据该接口的带宽自动计算其开销值。 计算公式&#xff1a; 接口开销 带宽参考值 / 接口带宽 &#xff08;取整数部分&#xff0c;结果小于1时取1&#xff09;通过改变带宽参考值可以间接改变接口的开…...

接口与实现-常用实用类-Java

接口与实现 接口 使用关键字interface来定义一个接口&#xff0c;接口的定义分为接口声明和接口体&#xff0c;例如&#xff1a; interface Com{ ....... } 接口声明 interface 接口的名字 接口体 接口体中的抽象方法和常量 接口体中所有抽象方法的访问权限一定都是pu…...

【CSS in Depth 2 精译】1.5 渐进式增强

文章目录 1.5 渐进式增强1.5.1 利用层叠规则实现渐进式增强1.5.2 渐进式增强的选择器1.5.3 利用 supports() 实现特性查询启用浏览器实验特性 1.5 渐进式增强 要用好 CSS 这样一门不断发展演进中的语言&#xff0c;其中一个重要的因素就是要与时俱进&#xff0c;及时了解哪些功…...

k8s集群master故障恢复笔记

剔除故障节点 kubectl drain master故障节点 kubectl delete node master故障节点 kubeadm reset rm -rf /etc/kubernetes/manifests mkdir -p /etc/kubernetes/pki/etcd/ 从master其他节点拷 scp /etc/kubernetes/pki/ca.crt ca.key sa.key sa.pub front-proxy-ca.crt …...

SMBIOS字符串逆向解析技巧:从二进制数据到硬件信息全解密(含Type1实例分析)

SMBIOS字符串逆向解析技巧&#xff1a;从二进制数据到硬件信息全解密&#xff08;含Type1实例分析&#xff09; 在数字取证和硬件分析领域&#xff0c;SMBIOS数据结构就像一台计算机的"身份证档案库"&#xff0c;存储着从主板序列号到电池规格等数百项硬件细节。但当…...

从风机并网振荡说起:手把手教你用Simulink设计VSG自适应阻尼,提升微网稳定性

新能源微网稳定性实战&#xff1a;基于Simulink的VSG自适应阻尼控制设计 当新能源发电占比超过30%时&#xff0c;微电网会面临一个尴尬的现状——传统同步发电机提供的旋转惯量大幅减少&#xff0c;系统变得像"玻璃杯"一样脆弱。去年参与某海岛微网项目时&#xff0c…...

【原创改进代码】面向绿证-碳交易的综合能源系统鲁棒优化方法附Python代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…...

颠覆式图像分层黑科技:layerdivider让设计效率提升95%的秘密

颠覆式图像分层黑科技&#xff1a;layerdivider让设计效率提升95%的秘密 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider 设计效率的革命性突破&#xff1…...

Win10自带应用太多?3分钟教你用PowerShell精准卸载(附常用应用命令大全)

Win10系统精简指南&#xff1a;PowerShell精准卸载内置应用全攻略 每次打开开始菜单&#xff0c;那些从未使用过的内置应用图标是否让您感到烦躁&#xff1f;作为技术从业者&#xff0c;我们更希望拥有一个干净高效的工作环境。本文将带您深入探索PowerShell在Windows系统管理中…...

Windows DLL注入工具Xenos实战指南:问题解决与效能优化

Windows DLL注入工具Xenos实战指南&#xff1a;问题解决与效能优化 【免费下载链接】Xenos Windows dll injector 项目地址: https://gitcode.com/gh_mirrors/xe/Xenos 引言 在Windows系统开发与调试过程中&#xff0c;DLL注入技术扮演着重要角色&#xff0c;无论是插件…...

保姆级教程:用sw_urdf_exporter插件将Solidworks机械臂模型转为ROS可用的URDF

从Solidworks到ROS&#xff1a;机械臂URDF转换全流程实战指南 机械臂作为工业自动化和服务机器人的核心部件&#xff0c;其运动仿真在ROS生态中占据重要地位。许多工程师习惯使用Solidworks进行机械结构设计&#xff0c;却苦于如何将设计成果无缝迁移到ROS环境。本文将彻底解决…...

OpenClaw镜像体验:Qwen3.5-9B云端部署避坑指南

OpenClaw镜像体验&#xff1a;Qwen3.5-9B云端部署避坑指南 1. 为什么选择云端镜像而非本地部署 去年冬天&#xff0c;当我第一次尝试在本地MacBook Pro上部署OpenClaw时&#xff0c;整整浪费了两个周末的时间。Node版本冲突、Python依赖缺失、CUDA驱动不兼容——这些看似简单…...

OpenClaw人人养虾:LiteLLM 统一网关

LiteLLM 是一个开源的 LLM API 统一网关&#xff08;Unified Gateway&#xff09;&#xff0c;支持 100 模型提供商&#xff0c;提供统一的 OpenAI 兼容 API 格式。 安装 LiteLLM pip 安装 pip install litellm[proxy] Docker 安装 docker run -p 4000:4000 \-e OPENAI_AP…...

2025届必备的六大AI学术工具解析与推荐

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 有一种人工智能开题报告辅助工具&#xff0c;它借助先进的自然语言处理技术与知识图谱技术构…...