日志与线程池
bit::Shadow✧(≖ ◡ ≖✿目录日志日志介绍日志的中心实现5个亮点0.策略模式1.gsepglobal seperator分隔符(兼容性极好缓冲区刷新行为)2.命名空间宏定义用户态接口3.重载递推返回4.enum class强枚举类型支持开发顺序线程池线程封装制作线程池框架图​编辑ThreadPool(int num)void HandlerTask()std::queue _taskqvoid Stop()宏的兼容bug日志日志介绍日志是软件系统中记录程序运行状态、事件和错误信息的机制是调试、监控和问题排查的核心工具。日志是什么日志是记录程序在运行过程中产生的结构化/半结构化的文本记录用于描述系统在特定时间点发生了什么。日志的输出常包含时间精确到秒日志类型INFO信息WARN警告产生位置详细信息。日志的中心实现仅实现日志中关键片段namespace LogModule { //枚举 gsep operator() operator 宏LOG(level)及另外两个 enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }; const std::string gsep \r\n;//换行平台兼容性考虑 //Win下记事本显示兼容 //Linux 下 \r 被忽略只识别 \n所以也兼容 //HTTP兼容 class LogMessage //设计外部类 { public: LogMessage() default; LogMessage(LogLevel level, std::string name, int line) : _level(level), _name(name), _line(line) { ; // #define自动 } ~LogMessage() {} //支持递推 // Log(LogLevel::DEBUG) hell world XXXX 3.14 1234 templatetypename T LogMessage operator(T t) { std::cout t; return LogMessage();//返回临时对象(右值属性)。---不能使用拷贝接受 } class Log { // Log(LogLevel::DEBUG) 这是一条日志; 末尾自动换行无需std::endl // 这是一条日志 LogMessage operator()(LogLevel level, std::string name, int line) { return LogMessage(level, name, line); } }; private: LogLevel _level; std::string _name; int _line; }; LogMessage Log;//用户端使用接口 //宏替换 #define Log(lv) LogMessage(lv, __FILE__, __LINE__) }5个亮点0.策略模式是开发基于的框架不是开发的顺序依赖。1.gsepglobal seperator分隔符(兼容性极好缓冲区刷新行为)//const char* gsep \r\n; const std::string gsep \r\n; //Win下记事本显示兼容 //Linux 下 \r被忽略只识别 \n所以也兼容 //HTTP兼容优化点std::string为什么利用string的自动扩容管理。支持接口类型很多更加灵活。2.命名空间宏定义用户态接口#define Log(lv) Logmessage(lv, __FILE__, __LINE__)注意点1.宏定义不要随意加注释内容。 易造成宏混乱2.lv与lv的传递兼容。 宏函数3.预处理宏__FILE__与__LINE__3.重载递推返回templateclass T //LogMessage ? LogMessage operator(T t) { //std::stringstream ss; //1.待纳入I/O流——处理换行刷新 return *this;拷贝返回接收 std::cout t; //2.简单实现 return LogMessage();!!! }注意点可以使用拷贝返回吗答不可以因为LogMessage()作为临时对象返回的右值属性!!!4.enum class强枚举类型支持enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL };开发顺序第1步核心基础设施↓第2步策略接口和具体策略↓第3步日志消息类核心↓第4步日志器组装↓第5步宏封装和全局对象待C进阶知识4.0线程池线程封装gitee#pragma once #includestring #includepthread.h #includefunctional #includeatomic // void* str static_castvoid*(s); //// 1.const char*不能直接转换为void*需要先使用const_cast去除const属性 #define RETERROR(s) \ do { \ void* str static_castvoid*(const_castchar*(s));\ pthread_exit(str);\ }while(0) ///2.使用pthread_exit而不是exit()进程退出 // static uint32_t number 3; namespace ThreadModule { //原子计数器操作 static std::atomicuint32_t number{1}; ///3. static uint32_t number 1;//1.生命周期全局。2.高平台兼容性。 using func_t std::functionvoid();////4.无参数无返回值的函数包装器 class Thread { private: ///5. 函数只能被内部访问无法被当做参数 static void* Route(void* arg)//static { Thread* self static_castThread*(arg); pthread_setname_np(self-pd, self-_name.c_str()); ///6. // self-_func;//回调新线程_func() self-_func();//回调新线程 // return (void*)(self-_name.c_str());//此处是主进程 return nullptr; } bool EnableDetach() { if (!_isRunning) return false; // detach线程状态变为unjionable,线程退出自动被主线程回收无需再join // pthread_detach(pd);//把新线程设置为分离了 _isDetach false; return true; } bool EnableRunning() { _isRunning true; return true; } public: Thread(func_t func) :_isRunning(false ) ,_isDetach(false) ,_func(func) ,res(nullptr) { //命名 _name thread- std::to_string(number); } ~Thread() { //7. if (_isDetach) pthread_exit(0);若对象在栈上会导致未定义行为 //若在堆上则不会被detach处理,会出错 } void Detach() { if (!_isRunning || _isDetach) return; EnableDetach(); } bool Start()//自定义设置新线程名字 { if(_isRunning) return false; int n pthread_create(pd, nullptr, Route, (void*)this); if(n) RETERROR(pthread_create); EnableRunning(); return true; } bool Stop() { //停止cancel if(_isRunning) { int n pthread_cancel(pd); if(n) RETERROR(cancel failed\n); } } void Join() { //等待新线程 if (!_isRunning || _isDetach) return; int n pthread_join(pd, res); if (n) RETERROR(join failed\n); } private: pthread_t pd; std::string _name; bool _isRunning; bool _isDetach; func_t _func; void* res; }; }制作线程池框架图“外部任务分配”模块暂不实现。ThreadPool(int num)构造函数指定申请线程个数。实现原理vector维护vectorThread _threads; // 线程群_num个线程。void HandlerTask(); 通过封装的线程构造参数被同等地分配到各个线程。ThreadPool(int num) : _num(num) { // 多线程创建与支持 for (int i 0; i _num; i) { // emplace_back()纳入 _threads.emplace_back([this]() { HandlerTask(); // lambda表达式返回值类型由编译器自动推导 }); // 纳入的类型取决于构造函数的参 // printf(1\n);//lambda仅是纳入并非直接调用 } // 传过去的this调用同一个函数这不就重入了 // 要的就是重入vector下重入 }void HandlerTask()维护任务队列支持并发。原理1.队列模板元编程。2.并发编程模板主操作——主操作边界条件像:满 空 打开失败等等—— (考虑并发问题)加锁/解锁——外部依赖像EQueue线程-考虑Pop与线程的通信唤醒条件——内部依赖线程池的单例模式GetInstance() { if(inc nullptr) //..... inc newThreadPoolT()“内部调用构造函数”}单if条件下——若快进程先new慢进程后判断nullptr。可能导致慢进程误判仍为空所以需要双重if。// 区别线程分发任务接口 void HandlerTask() // 对应using func_t // std::function(void());代表无参数无返回值的函数包装器 { // 处理任务。 // 线程名字(无并发问题) char name[128] {0}; pthread_getname_np(pthread_self(), name, sizeof(name)); while (true) { LockGuard _lock LockGuard(_mutex); // 内部加锁 // 锁区 { // 此处是while!!!防止伪等待 while (_taskq.empty() _isrunning) { // 线程等待 // 待被入队列的信号唤醒 _cond.Wait(_mutex); } // 处理完了具备退出背景 if (_taskq.empty() !_isrunning) { LOG(LogLevel::INFO) name 线程成功退出; break; } T t _taskq.front(); _taskq.pop(); } t(); // 任务执行(非临界区资源) } }难点1.想到新增_isrunning成员以调和线程存在情况。2.即将退出时Cond::BroadCast()的时机。std::queueT _taskq目的实现队列元素模板化自动构造。 // T承载函数(任务)类型。原理T t; 接受队列元素t(); 执行函数任务。//模板类型的前置声明 templatetypename T void QuTemp(); int main() { QuTempvoid (*)()(); return 0; } void Print() { printf(test\n); } templatetypename T void QuTemp() { //T队列维护函数。使用T对象运行 std::queueT _taskq; _taskq.push(Print); T t _taskq.front(); _taskq.pop(); t(); }void Stop()// 线程池退出 void Stop() { if (!_isrunning) return; _isrunning false; // handlerTask()需要改动目标是实现即使Stop()依然确保线程 任务完成后退出 // 休眠线程呢 为什么休眠线程要唤醒 主线程直接退出不可以吗 // 对于当前设计的线程池目标是完全可以主线程直接退出等待线程不予理睬。 // 但出于代码健壮性与可重复利用的价值还是处理为好。 // _cond.BroadCast(); WakeAThrd();//类内封装 }宏的兼容bug类型作用域兼容定义在命名空间内的宏虽然在命名空间内但是仍然属于全局即若.hpp内定义LOG(level)宏在其他文件内#includeLog.hpp文件即可使用该宏。但是报错位置很迷是LOG的位置。实际上原因是LogLevel的强枚举类型(enum class LogLevel)宏定义#中拥有使用了logger这一类名而导致的找不到同样的LogLeval也找不到。反思1.定位错误定位不要仅根据报错位置。2.画图明确框架包含关系制定解决方案。感谢支持长期连载欢迎关注

相关新闻

MySQL级联复制中server_id冲突的排查与解决

MySQL级联复制中server_id冲突的排查与解决

1. 问题背景与现象描述最近在维护一个MySQL级联复制环境时,遇到了一个典型的同步异常问题。环境拓扑是这样的:旧集群主库(Server A)→ 新集群主库(Server B)→ 新集群从库(Server C)…

2026/7/17 6:15:31阅读更多 →
哪家楼宇自控厂家/能耗监测系统厂家落地案例丰富?裕乾值得优先选择

哪家楼宇自控厂家/能耗监测系统厂家落地案例丰富?裕乾值得优先选择

一、引言楼宇自控/能耗监测系统是公共建筑、产业园区、工业厂区实现精细化能源管控、落实双碳目标、削减运营成本的核心数字化工具。伴随国家强制要求大型公建分项计量、能耗平台联网上报政策落地,市场需求从单一数据采集升级为集实时计量、异常预警、AI 能耗诊断、…

2026/7/17 6:15:31阅读更多 →
价值投资与价值投机:三大核心区别及长鑫存储IPO案例解析

价值投资与价值投机:三大核心区别及长鑫存储IPO案例解析

在金融投资领域,价值投资与价值投机是两种常见但本质不同的策略。许多投资者容易混淆这两者,导致在实际操作中出现策略摇摆、收益不稳的情况。本文将以长鑫存储IPO事件为背景,深入解析价值投机与价值投资的三大核心区别,帮助投资者…

2026/7/17 6:15:31阅读更多 →
DownKyi项目法律合规性分析:开源视频下载工具的法律边界与用户指南

DownKyi项目法律合规性分析:开源视频下载工具的法律边界与用户指南

DownKyi项目法律合规性分析:开源视频下载工具的法律边界与用户指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去…

2026/7/17 7:30:36阅读更多 →
cordova-plugin-ibeacon错误排查手册:常见问题与解决方案

cordova-plugin-ibeacon错误排查手册:常见问题与解决方案

cordova-plugin-ibeacon错误排查手册:常见问题与解决方案 【免费下载链接】cordova-plugin-ibeacon An iBeacon plugin for Phonegap / Cordova 3.x and upwards. Supports both iOS and Android (contributions are welcome) 项目地址: https://gitcode.com/gh_m…

2026/7/17 7:30:36阅读更多 →
如何快速掌握ExplorerPatcher:新手友好的Windows界面定制完整指南

如何快速掌握ExplorerPatcher:新手友好的Windows界面定制完整指南

如何快速掌握ExplorerPatcher:新手友好的Windows界面定制完整指南 【免费下载链接】ExplorerPatcher This project aims to enhance the working environment on Windows 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher 你是否也怀念Win…

2026/7/17 7:30:36阅读更多 →
HaE插件规则引擎加载异常的深度诊断与修复指南

HaE插件规则引擎加载异常的深度诊断与修复指南

HaE插件规则引擎加载异常的深度诊断与修复指南 【免费下载链接】HaE HaE是一款网络安全(数据安全)领域下的框架式项目,采用了乐高积木式模块化设计理念,巧妙地融入了人工智能大模型辅助技术,实现对HTTP消息&#xff08…

2026/7/17 7:30:36阅读更多 →
基于Docker的智能家居中枢:容器化部署与多协议集成实战

基于Docker的智能家居中枢:容器化部署与多协议集成实战

基于Docker的智能家居中枢:容器化部署与多协议集成实战 【免费下载链接】Home-AssistantConfig My Home Assistant configuration files 项目地址: https://gitcode.com/gh_mirrors/hom/Home-AssistantConfig Home Assistant配置实例展示了一个生产级的智能家…

2026/7/17 7:30:36阅读更多 →
三相PWM整流器第四象限PI双闭环解耦控制与Simulink仿真

三相PWM整流器第四象限PI双闭环解耦控制与Simulink仿真

如果你正在研究电力电子变换器,特别是需要实现能量双向流动的应用场景,那么三相电压型PWM整流器的第四象限运行绝对是一个绕不开的技术难点。传统整流器只能实现电网到负载的单向能量传输,而现代新能源发电、电机回馈制动等应用却要求系统能够…

2026/7/17 7:25:36阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/16 8:28:11阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/16 6:53:04阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/16 12:02:41阅读更多 →
VS Code 高效配置与个性化定制全攻略

VS Code 高效配置与个性化定制全攻略

1. VS Code 高效配置基础作为一款轻量级但功能强大的代码编辑器,VS Code 的默认配置已经能满足基本需求,但通过合理调整设置可以大幅提升编码效率。我使用 VS Code 已经有五年多时间,期间尝试过各种配置方案,总结出这套适合大多数…

2026/7/17 0:00:01阅读更多 →
从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

在异常检测领域,很多优秀算法最初都是以研究代码的形式发布的。它们能够在固定测试集上复现实验结果,却不一定能被普通用户直接拿来测试自己的图片。尤其是最近很多算法仅提供在固定测试集的测试环境,而gradio的demo演示也不会提供。 对工程应用和在自己的图片上进行测试来…

2026/7/17 0:00:01阅读更多 →
WinRAR高效配置指南:从基础安装到高级压缩实战

WinRAR高效配置指南:从基础安装到高级压缩实战

前几天帮同事处理一个客户发来的压缩包,解压时系统自带的工具弹出一串乱码,换用 WinRAR 却顺利打开了。这种看似简单的场景,恰恰暴露了不同压缩工具在处理非标准编码、分卷压缩或加密文件时的差异。WinRAR 作为一款老牌工具,真正价…

2026/7/17 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/16 20:13:14阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/16 8:58:42阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/16 17:10:26阅读更多 →