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

14.日志封装和线程池封装

一.日志与策略模式

像我们的linux中,也保存有相关的日志,如(/var/log/dmesg    /var/log/syslog等)

二.日志封装

1.makefile

bin=test_log
cc=g++
SRC=$(wildcard *.cc)
OBJ=$(SRC:.cc=.o)$(bin):$(OBJ)$(cc) -o $@ $^ -std=c++17 -lpthread
%.o:%.cc$(cc) -c $< -std=c++17.PHONY:clean
clean:rm -rf $(bin) $(OBJ)

2.日志框架实现

#pragma once#include <iostream>
#include <string>
#include <unistd.h>
#include "Mutex.hpp"namespace LogModule
{using namespace LockModule;//构成: 1. 构建日志字符串 2.刷新落盘(screen,file)//1.日志默认路径和文件名const std::string defaultlogpath = "./log/";const std::string defaultlogname = "log.txt";//2.日志等级enum class Loglevel{DEBUG = 1,INFO,WARNING,ERROR,FATAL};//3.刷新策略class LogStrategy{public:virtual ~LogStrategy() = default;//防止内存泄漏virtual void SyncLog(const std::string& message) = 0;};class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy(){}~ConsoleLogStrategy(){}void SyncLog(const std::string& message){LockGuard lockguard(_lock);std::cout << message << std::endl;}private:Mutex _lock;};class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string& logpath = defaultlogpath,const std::string& logname = defaultlogname):_logname(logname),_logpath(logpath){}~FileLogStrategy(){}void SyncLog(const std::string& message){LockGuard lockguard(_lock);std::cout << message << std::endl;}private:std::string _logpath;std::string _logname;Mutex _lock;};
}

3.文件日志实现

a.确定文件和路径存在

FileLogStrategy(const std::string& logpath = defaultlogpath,const std::string& logname = defaultlogname):_logname(logname),_logpath(logpath){LockGuard lockguard(_lock);//确认路径和文件名存在if(std::filesystem::exists(_logpath)){return;}try{std::filesystem::create_directories(_logpath);}catch(const std::filesystem::filesystem_error& e){std::cerr << e.what() << '\n'; }}

void SyncLog(const std::string& message){LockGuard lockguard(_lock);std::string log = _logpath + _logname; // ./log/log.txtstd::ofstream out(log,std::ios::app); //不存在就新建,存在就追加if(!out.is_open()){return;}// out.write(message.c_str(),sizeof(message));out << message << "\n";out.close();}

b.根据策略进行刷新

class Logger{public:Logger(){//默认采用屏幕刷新策略_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableConsleLog(){_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableFileLog(){_strategy = std::make_shared<FileLogStrategy>();}~Logger(){}private:std::shared_ptr<LogStrategy> _strategy;}

c.构建日志字符串

我们在Logger类的内部进行定义我们对应的日志字符串类

//一条完整的信息: [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] + 日志自定义部分class LogMessage{public:LogMessage(LogLevel level,const std::string& filename,int line):_currtime(CurrentTime()),_level(level),_pid(::getpid()),_filename(filename),_line(line){std::stringstream ssbuffer;ssbuffer << "[" << _currtime << "] " << "[" << LevelToString(_level) << "] "<< "[" << _pid << "] " << "[" << _filename <<"] "<< "[" << _line << "] " << " - ";_loginfo = ssbuffer.str();}template<class T>LogMessage& operator<<(const T& info){std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){}private:std::string _currtime; //日志时间LogLevel _level;       //日志等级pid_t _pid;            //进程pidstd::string _filename; //文件名称int _line;             //日志所在行号std::string _loginfo;  //一条完整的日志记录};

d.()的重载

LogMessage operator()(LogLevel level,const std::string& filename,int line){return LogMessage(level,filename,line);}

这里就是要进行拷贝返回

e.定义LOD()

Logger logger;
#define LOG(Level) logger(Level,__FILE__,__LINE__)

这里定义宏的好处:

在该文件进行调用时,会将代码进行宏替换到对应的文件,然后__FILE__和__LINE__就能识别是哪个代码的哪一行

f.__FILE__和__LINE__的使用

#include <stdio.h>int main()
{printf("%s:%d\n",__FILE__,__LINE__);printf("%s:%d\n",__FILE__,__LINE__);printf("%s:%d\n",__FILE__,__LINE__);return 0;
}

__FILE__就能获取我们对应的文件名,__LINE__能获取我们对应的文件行号

g.根据刷新策略进行刷新

class LogMessage{public:LogMessage(LogLevel level,const std::string& filename,int line,Logger& logger):_currtime(CurrentTime()),_level(level),_pid(::getpid()),_filename(filename),_line(line),_logger(logger){std::stringstream ssbuffer;ssbuffer << "[" << _currtime << "] " << "[" << LevelToString(_level) << "] "<< "[" << _pid << "] " << "[" << _filename <<"] "<< "[" << _line << "] " << " - ";_loginfo = ssbuffer.str();}template<class T>LogMessage& operator<<(const T& info){std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if(logger._strategy){logger._strategy->SyncLog(_loginfo);}}private:std::string _currtime; //日志时间LogLevel _level;       //日志等级pid_t _pid;            //进程pidstd::string _filename; //文件名称int _line;             //日志所在行号Logger& _logger;       //根据不同的策略进行刷新std::string _loginfo;  //一条完整的日志记录};

h.获取时间

//获取一些当前系统时间std::string CurrentTime(){time_t time_stamp = ::time(nullptr);struct tm curr;localtime_r(&time_stamp,&curr);char buffer[1024];snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",curr.tm_year + 1900,curr.tm_mon + 1,curr.tm_mday,curr.tm_hour,curr.tm_min,curr.tm_sec);return buffer;}// std::string GetCurrTime()// {//     time_t t = time(nullptr);//     struct tm* curr = ::localtime(&t);//     char currtime[32];//     snprintf(currtime,sizeof(currtime),"%d-%d-%d %d:%d:%d",//         curr->tm_year + 1900,//         curr->tm_mon + 1,//         curr->tm_mday,//         curr->tm_hour,//         curr->tm_min,//         curr->tm_sec//     );//     return currtime;// }

I.测试代码

#include "Log.hpp"using namespace LogModule;int main()
{LOG(LogLevel::DEBUG) << "hello world " << 3.14;LOG(LogLevel::DEBUG) << "hello world " << 5.21382;return 0;
}

J.查看宏替换(预处理)

k.转换刷新策略定义

#define ENABLE_CONSOLE_LOG() logger.EnableConsleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()

#include "Log.hpp"using namespace LogModule;int main()
{ENABLE_FILE_LOG();LOG(LogLevel::DEBUG) << "hello world " << 3.14;LOG(LogLevel::DEBUG) << "hello world " << 5.21382;return 0;
}

三.线程池介绍

四.线程池封装

1.将对应的Mutex.hpp等代码拷贝

"Thread.hpp"#ifndef _THREAD_HPP__
#define _THREAD_HPP__#include <iostream>
#include <string>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <functional>namespace ThreadModule
{using func_t = std::function<void()>;static int number = 1;enum class TSTATUS{NEW,RUN,STOP};class Thread{private://这个地方不能写成成员方法// void* Routine(Threadthis,void* args)// {// }static void* Routine(void* args){Thread* t = static_cast<Thread*>(args);t->_func();return nullptr;}void EnableDetach(){_joinable = false;}public:Thread(func_t func):_func(func),_status(TSTATUS::NEW),_joinable(true){_name = "Thread-" + std::to_string(number++);_pid = getpid();}bool Start(){if(_status != TSTATUS::RUN){int n = pthread_create(&_tid,nullptr,Routine,this);if(n != 0){return false;}_status = TSTATUS::RUN;return true;}return false;}bool Stop(){if(_status == TSTATUS::RUN){int n = pthread_cancel(_tid);if(n != 0){return false;}_status = TSTATUS::STOP;return true;}return false;}bool Join(){if(_joinable){int n = pthread_join(_tid,nullptr);if(n != 0){return false;}_status = TSTATUS::STOP;return true;}return false;}void Detach(){EnableDetach();pthread_detach(_tid);}bool IsJoinable(){return _joinable;}std::string Name(){return _name;}~Thread(){}private:std::string _name;pthread_t _tid;pid_t _pid;bool _joinable;//默认不分离func_t _func;TSTATUS _status;};
};#endif
"Mutex.hpp"#pragma once
#include <iostream>
#include <pthread.h>namespace LockModule
{class Mutex{public:Mutex(const Mutex&) = delete;const Mutex& operator=(const Mutex&) = delete;Mutex(){int n = ::pthread_mutex_init(&_lock,nullptr);(void)n;}void Lock(){int n = ::pthread_mutex_lock(&_lock);(void)n;}void Unlock(){int n = ::pthread_mutex_unlock(&_lock);(void)n;}pthread_mutex_t* LockPtr(){return &_lock;}~Mutex(){int n = ::pthread_mutex_destroy(&_lock);(void)n;}private:pthread_mutex_t _lock;};class LockGuard{public:LockGuard(Mutex& mtx):_mtx(mtx){_mtx.Lock();}~LockGuard(){_mtx.Unlock();}private:Mutex& _mtx;};
};
"Log.hpp"#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <unistd.h>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <memory>
#include <time.h>
#include "Mutex.hpp"namespace LogModule
{using namespace LockModule;//构成: 1. 构建日志字符串 2.刷新落盘(screen,file)//1.日志默认路径和文件名const std::string defaultlogpath = "./log/";const std::string defaultlogname = "log.txt";//2.日志等级enum LogLevel{DEBUG = 1,INFO,WARNING,ERROR,FATAL};std::string LevelToString(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 "None";}}//3.刷新策略class LogStrategy{public:virtual ~LogStrategy() = default;//防止内存泄漏virtual void SyncLog(const std::string& message) = 0;};class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy(){}~ConsoleLogStrategy(){}void SyncLog(const std::string& message){LockGuard lockguard(_lock);std::cout << message << std::endl;}private:Mutex _lock;};class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string& logpath = defaultlogpath,const std::string& logname = defaultlogname):_logname(logname),_logpath(logpath){LockGuard lockguard(_lock);//确认路径和文件名存在if(std::filesystem::exists(_logpath)){return;}try{std::filesystem::create_directories(_logpath);}catch(const std::filesystem::filesystem_error& e){std::cerr << e.what() << '\n'; }}~FileLogStrategy(){}void SyncLog(const std::string& message){LockGuard lockguard(_lock);std::string log = _logpath + _logname; // ./log/log.txtstd::ofstream out(log,std::ios::app); //不存在就新建,存在就追加if(!out.is_open()){return;}// out.write(message.c_str(),sizeof(message));out << message << "\n";out.close();}private:std::string _logpath;std::string _logname;Mutex _lock;};//获取一些当前系统时间std::string CurrentTime(){time_t time_stamp = ::time(nullptr);struct tm curr;localtime_r(&time_stamp,&curr);char buffer[1024];snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",curr.tm_year + 1900,curr.tm_mon + 1,curr.tm_mday,curr.tm_hour,curr.tm_min,curr.tm_sec);return buffer;}// std::string GetCurrTime()// {//     time_t t = time(nullptr);//     struct tm* curr = ::localtime(&t);//     char currtime[32];//     snprintf(currtime,sizeof(currtime),"%d-%d-%d %d:%d:%d",//         curr->tm_year + 1900,//         curr->tm_mon + 1,//         curr->tm_mday,//         curr->tm_hour,//         curr->tm_min,//         curr->tm_sec//     );//     return currtime;// }//4.构建日志字符串,根据策略进行刷新class Logger{public:Logger(){//默认采用屏幕刷新策略_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableConsleLog(){_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableFileLog(){_strategy = std::make_shared<FileLogStrategy>();}~Logger(){}//一条完整的信息: [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] + 日志自定义部分class LogMessage{public:LogMessage(LogLevel level,const std::string& filename,int line,Logger& logger):_currtime(CurrentTime()),_level(level),_pid(::getpid()),_filename(filename),_line(line),_logger(logger){std::stringstream ssbuffer;ssbuffer << "[" << _currtime << "] " << "[" << LevelToString(_level) << "] "<< "[" << _pid << "] " << "[" << _filename <<"] "<< "[" << _line << "] " << " - ";_loginfo = ssbuffer.str();}template<class T>LogMessage& operator<<(const T& info){std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if(_logger._strategy){_logger._strategy->SyncLog(_loginfo);}}private:std::string _currtime; //日志时间LogLevel _level;       //日志等级pid_t _pid;            //进程pidstd::string _filename; //文件名称int _line;             //日志所在行号Logger& _logger;       //根据不同的策略进行刷新std::string _loginfo;  //一条完整的日志记录};LogMessage operator()(LogLevel level,const std::string& filename,int line){return LogMessage(level,filename,line,*this);}private:std::shared_ptr<LogStrategy> _strategy;};Logger logger;
#define LOG(Level) logger(Level,__FILE__,__LINE__)
#define ENABLE_CONSOLE_LOG() logger.EnableConsleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()//LOG(DEBUG) << xx << aa << bb;
//LOgMessage << xx << aa << bb;
}
"Cond.hpp"#pragma once#include <iostream>
#include <pthread.h>
#include "Mutex.hpp"namespace CondModule
{using namespace LockModule;class Cond{public:Cond(){int n = ::pthread_cond_init(&_cond,nullptr);(void)n;}void Wait(Mutex& mutex)//让线程曾经的锁释放曾经的锁{int n = ::pthread_cond_wait(&_cond,mutex.LockPtr());(void)n;}void Notify(){int n = ::pthread_cond_signal(&_cond);(void)n;}void NotifyAll(){int n = ::pthread_cond_broadcast(&_cond);(void)n;}~Cond(){int n = ::pthread_cond_destroy(&_cond);(void)n;}private:pthread_cond_t _cond;};
}

2.线程池框架设计

#pragma once#include <iostream>
#include <string>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"namespace ThreadPoolModule
{using namespace LogModule;using namespace ThreadModule;using namespace LockModule;using namespace CondModule;const static int defaultnum = 5;class ThreadPool{public:ThreadPool(){}void Equeue(){}void Start(){}void Stop(){}~ThreadPool(){}private:};
}

3.构造函数

ThreadPool(int num = defaultnum):_num(num){for(int i = 0;i < _num;i++){_threads.push_back(std::make_shared<Thread>(DefaultTest));LOG(LogLevel::DEBUG) << "构建线程" << _threads[i]->Name() << "对象 ... 成功";}}

4.Start()

void Start(){for(auto& thread_ptr : _threads){thread_ptr->Start();LOG(LogLevel::DEBUG) << "启动线程" << thread_ptr->Name() << " ... 成功";}}

5.Wait()

void Wait(){for(auto& thread_ptr : _threads){thread_ptr->Join();LOG(LogLevel::DEBUG) << "停止线程" << thread_ptr->Name() << " ... 成功";}}

6.线程处理任务

bool IsEmpty(){return _taskq.empty();}void HandlerTask(){while(true){//1.拿任务T t;{LockGuard lockguard(_lock);while(IsEmpty()){_cond.Wait(_lock);}t = _taskq.front();_taskq.pop();}//2.处理任务t(); //规定,未来所有的任务处理,全部都是必须提供()方法!}}

7.唤醒线程

void Equeue(T& in){LockGuard lockguard(_lock);_taskq.push(std::move(in));if(_wait_num > 0){_cond.Notify();}}

8.任务类的创建

#pragma once#include <iostream>
#include <functional>
#include "Log.hpp"using task_t = std::function<void()>;
using namespace LogModule;void Push()
{LOG(LogLevel::DEBUG) << "我是一个推送数据到服务器的一个任务,我正在被执行";
}

9.测试代码

#include "ThreadPool.hpp"
#include "Task.hpp"
#include <memory>using namespace ThreadPoolModule;int main()
{ENABLE_CONSOLE_LOG();std::unique_ptr<ThreadPool<task_t>> tp = std::make_unique<ThreadPool<task_t>>();tp->Start();int cnt = 10;while(cnt){tp->Equeue(Push);cnt--;}// tp->Stop();tp->Wait();return 0;
}

http://www.dtcms.com/a/594719.html

相关文章:

  • 呼和浩特做网站哪家好网站上线备案
  • 鼓楼徐州网站开发东莞通app打不开
  • 免费建站模板哪个好怎么查看自己网站有没有做301
  • 新网站如何让百度收录wordpress非代码方式添加备案号
  • COM组件
  • 如何构建加密货币分钟级回测系统(整体设计说明)
  • 手术相关公开数据集收集报告
  • 智能座舱知识图谱技术架构方案
  • 怎么用polylang做网站娶妻为什么不娶外贸女
  • 做网站和推广的公司哪家好网站跳出率一般是多少
  • 用什么做网站开发苏州网站开发公司哪里济南兴田德润简介
  • 湖北网站seo设计兰州模板型网站建设
  • 彩虹网站建设营销技巧电影
  • ROS2学习记录——TF坐标变换工具(二)
  • wordpress音乐站源码国内知名展示设计公司
  • 坂田建设网站做网站首页应该考虑什么
  • 怎么样搭建qq号网站网站怎样排版
  • Redis实现未读消息计数
  • 制作属于自己的网站伪静态网站入侵
  • 企业站用什么程序做网站运城网站建设
  • 景区智慧旅游网站建设多网站怎么做seo
  • html5 网站后台建筑用工平台
  • 画世界笔刷免费合集:含导入教程与全风格推荐
  • Cache-Aside模式下Redis与MySQL数据一致性问题分析
  • 做任务 网站随州网站制作
  • 2025-11-10
  • 网站艺术设计redis wordpress 设置
  • 建立外贸英文网站应该怎么做英文网站注册
  • 芝罘网站建设设计手机网站软件
  • 11.10 脚本算法 五子棋 「重要」