muduo异步日志
muduo异步日志实现
陈硕老师的muduo网络库的异步日志的实现,今晚有点晚了,我明晚再把这个异步日志抽出来,作为一个独立的日志库。
所在文件
-
AsyncLogging.cc
-
AsyncLogging.h
-
LogFile.h
-
LogFile.cc
-
CountDownLatch.h
-
CountDownLatch.cc
这个CountDownLatch有点像信号量,但是又只有down操作,上网查了以下类似的,作用有点像屏障
class AsyncLogging : noncopyable
{public:AsyncLogging(const string& basename,off_t rollSize,int flushInterval = 3);~AsyncLogging(){if (running_){stop();}}void append(const char* logline, int len);void start(){running_ = true;thread_.start(); // 启动线程latch_.wait(); // 这里的wait调用其实并不会阻塞// 主线程}void stop() NO_THREAD_SAFETY_ANALYSIS{running_ = false;cond_.notify();thread_.join();}private:// 默认的守护进程执行的函数void threadFunc();/*Buffer的数据结构private:std::vector<char> buffer_;size_t readerIndex_;size_t writerIndex_;static const char kCRLF[];*/typedef muduo::detail::FixedBuffer<muduo::detail::kLargeBuffer> Buffer;typedef std::vector<std::unique_ptr<Buffer>> BufferVector;typedef BufferVector::value_type BufferPtr; // 表示容器元素的类型const int flushInterval_; // 刷盘的时间间隔std::atomic<bool> running_; // 是否运行const string basename_; // 文件名const off_t rollSize_; // 日志回滚的大小muduo::Thread thread_; // 日志类自带一个守护线程来写muduo::CountDownLatch latch_; muduo::MutexLock mutex_;muduo::Condition cond_ GUARDED_BY(mutex_);BufferPtr currentBuffer_ GUARDED_BY(mutex_); // 当前缓冲BufferPtr nextBuffer_ GUARDED_BY(mutex_); // 预备缓冲BufferVector buffers_ GUARDED_BY(mutex_); // 已经写满并等待落盘的缓冲
};
#include <stdio.h>using namespace muduo;AsyncLogging::AsyncLogging(const string& basename,off_t rollSize,int flushInterval): flushInterval_(flushInterval),running_(false),basename_(basename),rollSize_(rollSize),thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"),latch_(1),mutex_(),cond_(mutex_),currentBuffer_(new Buffer),nextBuffer_(new Buffer),buffers_()
{currentBuffer_->bzero();nextBuffer_->bzero();buffers_.reserve(16);
}void AsyncLogging::append(const char* logline, int len)
{muduo::MutexLockGuard lock(mutex_);if (currentBuffer_->avail() > len){currentBuffer_->append(logline, len);}else{buffers_.push_back(std::move(currentBuffer_));if (nextBuffer_){currentBuffer_ = std::move(nextBuffer_);}else{// 四个缓冲区都写满了currentBuffer_.reset(new Buffer); // Rarely happens}currentBuffer_->append(logline, len);// 这里的notify不一定什么时候都有效// 如果此时守护线程正在工作// 那么这个信后就会丢失,但是没有造成影响// 但是有可能守护线程正在条件变量上睡眠cond_.notify();}
}void AsyncLogging::threadFunc()
{assert(running_ == true);latch_.countDown(); // 计数器减一,latch_ == 0,并唤醒主线程LogFile output(basename_, rollSize_, false); // 初始化一个输出流BufferPtr newBuffer1(new Buffer);BufferPtr newBuffer2(new Buffer);newBuffer1->bzero();newBuffer2->bzero();BufferVector buffersToWrite; // 相当于一个前后端交互的单元// 将写满的buffer装到vector中// 在传输到后端buffersToWrite.reserve(16);while (running_){assert(newBuffer1 && newBuffer1->length() == 0);assert(newBuffer2 && newBuffer2->length() == 0);assert(buffersToWrite.empty());{muduo::MutexLockGuard lock(mutex_);// 使用条件变量完成定时任务if (buffers_.empty()) // unusual usage!{cond_.waitForSeconds(flushInterval_);}buffers_.push_back(std::move(currentBuffer_));currentBuffer_ = std::move(newBuffer1);buffersToWrite.swap(buffers_); // buffers_变成一个空的buffers_if (!nextBuffer_){nextBuffer_ = std::move(newBuffer2);}}assert(!buffersToWrite.empty());// 如果日志太多了if (buffersToWrite.size() > 25){char buf[256];snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n",Timestamp::now().toFormattedString().c_str(),buffersToWrite.size()-2);fputs(buf, stderr);// 先输出一个报警的日志output.append(buf, static_cast<int>(strlen(buf)));// 清除多余的日志buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end());}for (const auto& buffer : buffersToWrite){// FIXME: use unbuffered stdio FILE ? or use ::writev ?output.append(buffer->data(), buffer->length());}if (buffersToWrite.size() > 2){// drop non-bzero-ed buffers, avoid trashing// vector底层是智能指针不用担心内存泄露buffersToWrite.resize(2);}if (!newBuffer1){assert(!buffersToWrite.empty());newBuffer1 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer1->reset();}if (!newBuffer2){assert(!buffersToWrite.empty());newBuffer2 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer2->reset();}buffersToWrite.clear();output.flush();}output.flush();
}
相关文章:
muduo异步日志
muduo异步日志实现 陈硕老师的muduo网络库的异步日志的实现,今晚有点晚了,我明晚再把这个异步日志抽出来,作为一个独立的日志库。 所在文件 AsyncLogging.cc AsyncLogging.h LogFile.h LogFile.cc CountDownLatch.h CountDownLatch.cc…...
在智慧能源的发展历程中,哪些技术的出现起到了关键性的作用?
智慧能源作为一种全新的能源发展理念,正逐渐成为能源领域的热门话题。在智慧能源的发展历程中,有许多技术的出现起到了关键性的作用,推动了智慧能源的快速发展。 一、物联网技术 物联网技术使得能源设备可以实现互联互通,通过传感…...

SQLiteC/C++接口详细介绍sqlite3_stmt类(十三)
返回:SQLite—系列文章目录 上一篇:SQLiteC/C接口详细介绍sqlite3_stmt类(十二) 下一篇: 待续 51、sqlite3_stmt_scanstatus_reset sqlite3_stmt_scanstatus_reset 函数用于重置指定语句对象最近一次执行的 WHER…...
扫雷(蓝桥杯,acwing)
题目描述: 扫雷是一种计算机游戏,在 2020 世纪 80 年代开始流行,并且仍然包含在某些版本的 Microsoft Windows 操作系统中。 在这个问题中,你正在一个矩形网格上玩扫雷游戏。 最初网格内的所有单元格都呈未打开状态。 其中 M个…...

macOS 通过 MacPorts 正确安装 MySQL 同时解决无法连接问题
如果你通过 sudo port install 命令正常安装了 MySQL,再通过 sudo port load 命令启动了 MySQL Server,此刻却发现使用 Navicat 之类的 GUI 软件无法连接,始终返回无法连接到 127.0.0.1 服务器。这是一个小坑,因为他默认使用了 So…...
Semi-supervised Open-World Object Detection
Semi-supervised Open-World Object Detection 摘要1 介绍2.准备工作提出的SS-OWOD问题设置2.1 基础架构3 方法3.1整体架构摘要 传统的开放世界对象检测(OWOD)问题设置首先区分已知和未知类别,然后在后续任务中引入标签时逐步学习未知对象。然而,当前的OWOD公式在增量学习…...
C语言实现射击小游戏
以下是一个简单的C语言射击小游戏的实现示例。这个游戏中,玩家控制一个飞船,敌方飞船会随机出现并向玩家移动。如果玩家的飞船与敌方飞船相撞,玩家就失去一条生命,代码如下: #include <stdio.h> #include <s…...
c++11 标准模板(STL)本地化库 - std::islower(std::locale) 检查字符是否被本地环境分类为小写
本地化库 本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析,以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C 标准库的其他组件的行为。 检查字符是否被本地环境分类为小写 std::islower(std::locale) template&…...

粘度指数改进剂市场需求增长 为润滑油添加剂细分产品
粘度指数改进剂市场需求增长 为润滑油添加剂细分产品 粘度指数改进剂是一种油溶性高分子聚合物,主要用于提高润滑油粘度以及粘度指数。粘度指数改进剂具有稠化能力强、抗磨性好、热稳定性好等优势,可添加于液压油、内燃机油以及齿轮油等油品中。 …...

LabVIEW柴油机安保监控系统
LabVIEW柴油机安保监控系统 随着航运业的快速发展,确保船舶柴油机的安全稳定运行变得尤为重要。船舶柴油机故障不仅会导致重大的经济损失,还可能危及人员安全和环境。设计并开发了一套基于LabVIEW平台的柴油机安保监控系统,旨在通过实时监控…...

实测国内AI大模型问答效果
随着ChatGPT热度的攀升,越来越多的公司也相继推出了自己的AI大模型。按照github工程awesome-LLMs-In-China所列举的,现如今国内AI大模型已达243个,比较著名的有文心一言、通义千问等。各大应用也开始内置AI玩法,如抖音的AI特效。下…...
不得不等待的无奈 -《葡萄成熟时》
恋上一个人便是撒下一颗葡萄种子,你可能会坚持,但不一定会结果,收获(在一起)。 更有可能得到的是枯枝烂叶(ta的离开)。 就算你再努力,再用心去栽培(为ta付出࿰…...
【Python】Python中装饰器和魔法方法的区别
在Python中,装饰器(Decorators)和魔法方法(Magic Methods)是两种不同的高级特性,分别服务于不同的目的。 装饰器 (Decorators) 装饰器是一种强大的工具,它可以修改或增强函数、方法或类的行为…...
【React】创建你的第一个React组件
要使用React创建你的第一个组件,首先确保你已经安装了Node.js和npm(Node包管理器)。然后,你可以通过npm安装Create React App这个官方支持的脚手架工具来快速生成一个新的React应用项目,该项目包含了React、ReactDOM、…...

五分钟搞懂MySQL索引下推
什么是索引下推 索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6版本的新特性,它能减少回表查询次数,提高查询效率。 索引下推优化的原理 我们先简单了解一下MySQL大概的架构: MySQL服务层负责SQL语法解析、…...
【数据库】SQL如何添加数据
在SQL中,您可以使用INSERT INTO语句来添加数据到数据库表中。以下是一些基本的示例和解释: 1.插入完整行数据: 如果您想为表中的每一列都插入数据,那么可以不必指定列名。但是,您需要为每一列都提供数据,并…...

ClickHouse01-什么是ClickHouse
什么是ClickHouse? 关于发展历史存在的优势与劣势什么是它风靡的原因? 什么是ClickHouse? 官方给出的回答是,它是一个高性能、列式存储、基于SQL、供在线分析处理的数据库管理系统 当然这边不得不提到OLAP(Online Analytical Pr…...
使用Docker搭建Nascab
使用Docker来部署Nascab能够让这个过程变得更加灵活和便捷,因为Docker可以在隔离的环境中运行应用程序,简化了部署和配置的复杂性。 使用Docker CLI部署Nascab docker run -d \ --name nascab \ -p 18080:80 \ -p 18443:443 \ -p 18090:90 \ -p 18021:…...

Elasticsearch8.x版本Java客户端Elasticsearch Java API 如何并发修改
前言 并发控制,一般有两种方案,悲观锁和乐观锁,其中悲观锁是默认每次更新操作肯定会冲突,所以每次操作都要先获取锁,操作完毕再释放锁,适用于写比较多的场景。而乐观锁是默认每次更新操作都不会冲突&#…...

Docker 安装 Skywalking以及UI界面
关于Skywalking 在现代分布式系统架构中,应用性能监控(Application Performance Monitoring, APM)扮演着至关重要的角色。本文将聚焦于一款备受瞩目的开源APM工具——Apache Skywalking,通过对其功能特性和工作原理的详细介绍&am…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...