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

29.线程的互斥与同步(三)

池化技术:预制,减少系统调用的次数,提高效率。

日志

完整代码:

#ifndef __LOG_HPP__
#define __LOG_HPP__#include <iostream>
#include <string>
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <sys/types.h>
#include <ctime>
#include "Mutex.hpp"namespace LogModule
{using namespace MutexModule;// 日志刷新策略class LogStrategy{public:~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 控制台刷新class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy(){}~ConsoleLogStrategy(){}virtual void SyncLog(const std::string &message) override{MutexGuard mutexguard(_mutex);std::cout << message << std::endl;}private:Mutex _mutex;};static const std::string default_path = "./log";static const std::string default_file = "my.log";static const std::string sep = "\r\n";// 文件刷新class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &path = default_path, const std::string &file = default_file): _path(path), _file(file){{// 保证多线程时的线程安全MutexGuard mutexguard(_mutex);// 如果已经存在目录,返回if (std::filesystem::exists(_path))return;try{// 创建目录结构std::filesystem::create_directories(_path);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << std::endl;}}}~FileLogStrategy(){}virtual void SyncLog(const std::string &message) override{std::string pathname = _path + (_path.back() == '/' ? "" : "/") + _file;// 以追加方式打开文件std::ofstream ofs(pathname, std::ios::app);ofs << message << sep;ofs.close();}private:std::string _path;std::string _file;Mutex _mutex;};enum class LogLevel{DEBUG,INFO,WARNING,ERROR,FATAL};std::string GetLevel(LogLevel level){switch (level){case LogLevel::DEBUG:return "DEBUG";case LogLevel::INFO:return "INFO";case LogLevel::WARNING:return "WARNING";case LogLevel::ERROR:return "ERROR";case LogLevel::FATAL:return "FATAL";default:return "UNKNOWN";}}std::string GetTime(){time_t timestamp = time(nullptr);struct tm data;localtime_r(&timestamp, &data);char buff[128];snprintf(buff, 128, "%4d-%02d-%02d %02d:%02d:%02d",data.tm_year + 1900,data.tm_mon + 1,data.tm_mday,data.tm_hour,data.tm_min,data.tm_sec);return buff;}class Log{public:Log(){}~Log(){}void EnableConsoleLogStrategy(){_sl = std::make_unique<ConsoleLogStrategy>();}void EnableFileLogStrategy(){_sl = std::make_unique<FileLogStrategy>();}// 格式化的左边消息class LogInfo{public:LogInfo(Log *log, LogLevel level, const std::string &filename, const unsigned int line): _time(GetTime()), _level(level), _pid(getpid()), _filename(filename), _line(line), _log(log){std::stringstream ss;ss << "[" << _time << "] "<< "[" << GetLevel(_level) << "] "<< "[" << _pid << "] "<< "[" << _filename << "] "<< "[" << _line << "] "<< "- ";_message = ss.str();}// LogInfo销毁时,刷新~LogInfo(){if (_log->_sl){_log->_sl->SyncLog(_message);}}template <typename T>LogInfo &operator<<(const T &data){std::stringstream ss;ss << data;_message += ss.str();return *this;}private:std::string _time;     // 时间,年月日时分秒LogLevel _level;       // 日志等级pid_t _pid;            // 进程pidstd::string _filename; // 打印日志对应的文件名unsigned int _line;    // 行号std::string _message;  // 整条信息,左边+右边// Log的指针Log *_log;};// 重载函数调用,用仿函数的形式调用,且隐式传递自己的this指针// 返回LogInfo的匿名对象,生命周期只有一行,一行结束就调用析构,刷新。LogInfo operator()(LogLevel level, const std::string &filename, const unsigned int line){return LogInfo(this, level, filename, line);}private:std::unique_ptr<LogStrategy> _sl; // 策略基类指针};Log log;
#define Enable_Console_log_Strategy() log.EnableConsoleLogStrategy()
#define Enable_File_log_Strategy() log.EnableFileLogStrategy()
#define LOG(level) log(level, __FILE__, __LINE__)
}#endif

效果:

调用:

        Enable_Console_log_Strategy();

        Enable_File_log_Strategy();

        LOG(LogLevel::DEBUG) << "hello world";

细节点1:

时间相关函数<time.h>

struct tm *localtime_r(const time_t *timep, struct tm *result);

参数timep为时间戳,可通过time(nullptr);获取

参数result为输出型参数

细节点2:

多线程情况下,目录结构为临界资源,需要加锁。同样的,显示器文件也要加锁。

细节点3:

对于日志右边信息处理时,为了使用便利。重载流插入,并以模板的形式,支持stringstream流插入支持的类型。返回值返回引用,用于连续多次插入。

细节点4:

采用返回LogInfo的匿名对象,生命周期只有一行,一行结束就调用析构,析构中在设置刷新,就可以达到一行一行刷新日志的目的。

细节点5:

Log.hpp中定义一个全局的Log类型的变量。

采用宏替换和预处理的两个宏:__FILE__(文件名),__LINE__(行号)

使得使用更加便利和雅观。


文章转载自:

http://gclXmX5L.dfwkn.cn
http://Z4BlVp2U.dfwkn.cn
http://WxKmEQYD.dfwkn.cn
http://y2nXO1C1.dfwkn.cn
http://2thyAGzI.dfwkn.cn
http://aulUNree.dfwkn.cn
http://qdLT66zr.dfwkn.cn
http://9KAD3oLK.dfwkn.cn
http://sC9Tn85d.dfwkn.cn
http://PRyD7MnC.dfwkn.cn
http://jUhPWvHA.dfwkn.cn
http://0oawM1kg.dfwkn.cn
http://QPJfp7De.dfwkn.cn
http://pBCPt1ys.dfwkn.cn
http://7YtITzW3.dfwkn.cn
http://SL739UAZ.dfwkn.cn
http://tkbo4gf0.dfwkn.cn
http://jFGihLNn.dfwkn.cn
http://M4octx0w.dfwkn.cn
http://vNEBhLJh.dfwkn.cn
http://XrlUvMyv.dfwkn.cn
http://KqHzouYA.dfwkn.cn
http://TRd8myOi.dfwkn.cn
http://0GaIe7Sm.dfwkn.cn
http://X0Hq49hV.dfwkn.cn
http://iHEZyxhV.dfwkn.cn
http://Cx0cl2E1.dfwkn.cn
http://3hF9yzKj.dfwkn.cn
http://H5TJVOap.dfwkn.cn
http://KhIrfdrN.dfwkn.cn
http://www.dtcms.com/a/379380.html

相关文章:

  • 第3节-使用表格数据-DEFAULT约束
  • linux系统安装wps
  • 26. AI-Agent-LangChain
  • 基于51单片机温度控制系统报警器恒温箱蓝牙app控制设计
  • 2025 年 GPU 显卡维修市场:高性能计算时代的刚需支撑
  • 融智学新范式(1992-2000)被认为是先于谷歌同类探索的更全面更深刻的理论研究和实践应用
  • 领码方案|Windows 下 PLT → PDF 转换服务超级完整版:异步、权限、进度
  • IvorySQL 适配 LoongArch® 龙架构
  • 公寓智能水电门锁管理系统:一套系统,彻底重构租赁管理逻辑
  • 从伦理保障到病史管理,武汉大学等提出Healthcare Agent,问诊主动性及相关性超越GPT-4等闭源模型
  • 华为交换机VLAN技术基础1(VLAN划分及跨交换机相同VLAN的通信技术)
  • Python自动化测试实现思路
  • python学习进阶之异常和文件操作(三)
  • vue3源码学习(三)computed 源码学习
  • 94. 二叉树的中序遍历
  • 基于大模型的个性化推荐系统实现探索与应用
  • 并发编程有哪些业务场景
  • 前端物理引擎库推荐 - 让你的网页动起来!
  • 考华为认证可从事哪些工作?
  • 【Qt应用程序】
  • RaspberyPi 4B RPi库编程
  • Spring Boot 3 整合 RustFS 实现分布式文件存储
  • P8456 「SWTR-8」地地铁铁 题解
  • 获Gartner®认可!锐捷入选2025年Gartner园区网络基础设施管理与运营软件市场指南
  • 告别环境地狱!Java生态“AI原生”解决方案入驻 GitCode​
  • 【leetcode】322. 零钱兑换
  • 数据清洗:缺失值、异常值与重复数据处理全解析
  • 审计过程中常见的文档缺失问题如何避免
  • 图像投影(透视)变换
  • Spring Cloud Gateway:下一代API网关的深度解析与实战指南