线程-8-日志_线程池
主要看code
日志:
日志指标/属性
设计模式:策略模式
日志格式:
[可读性很好的时间] [⽇志等级] [进程pid] [打印对应⽇志的⽂件名][⾏号] - 消息内容,⽀持可
变参数
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [17] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [18] - hello world
code
完整详细代码:https://gitee.com/whb-helloworld/112/blob/master/code/lesson32/
Log
log.hpp
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream>
#include <memory>
#include <filesystem> //C++17
#include <unistd.h>
#include <time.h>
#include "Mutex.hpp"
namespace LogMudule
{
using namespace LockModule;
// 获取一下当前系统的时间
std::string CurrentTime()
{
time_t time_stamp = ::time(nullptr);
struct tm curr;
localtime_r(&time_stamp, &curr); // 时间戳,获取可读性较强的时间信息5
char buffer[1024];
// bug
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;
}
// 构成: 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
};
std::string Level2String(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;
};
// 3.1 控制台策略
class ConsoleLogStrategy : public LogStrategy
{
public:
ConsoleLogStrategy()
{
}
~ConsoleLogStrategy()
{
}
void SyncLog(const std::string &message)
{
LockGuard lockguard(_lock);
std::cout << message << std::endl;
}
private:
Mutex _lock;
};
// 3.2 文件级(磁盘)策略
class FileLogStrategy : public LogStrategy
{
public:
FileLogStrategy(const std::string &logpath = defaultlogpath, const std::string &logname = defaultlogname)
: _logpath(logpath),
_logname(logname)
{
// 确认_logpath是存在的.
LockGuard lockguard(_lock);
if (std::filesystem::exists(_logpath))
{
return;
}
try
{
std::filesystem::create_directories(_logpath);
}
catch (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.txt
std::ofstream out(log, std::ios::app); // 日志写入,一定是追加
if (!out.is_open())
{
return;
}
out << message << "\n";
out.close();
}
private:
std::string _logpath;
std::string _logname;
// 锁
Mutex _lock;
};
// 日志类: 构建日志字符串, 根据策略,进行刷新
class Logger
{
public:
Logger()
{
// 默认采用ConsoleLogStrategy策略
_strategy = std::make_shared<ConsoleLogStrategy>();
}
void EnableConsoleLog()
{
_strategy = std::make_shared<ConsoleLogStrategy>();
}
void EnableFileLog()
{
_strategy = std::make_shared<FileLogStrategy>();
}
~Logger() {}
// 一条完整的信息: [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] + 日志的可变部分(<< "hello world" << 3.14 << a << b;)
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 << "] "
<< "[" << Level2String(_level) << "] "
<< "[" << _pid << "] "
<< "[" << _filename << "] "
<< "[" << _line << "] - ";
_loginfo = ssbuffer.str();
}
template <typename 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; // 进程pid
std::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.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()
}
Main.cc
#include "Log.hpp"
using namespace LogMudule;
int main()
{
ENABLE_FILE_LOG();
LOG(LogLevel::DEBUG) << "hello file";
LOG(LogLevel::DEBUG) << "hello file";
LOG(LogLevel::DEBUG) << "hello file";
LOG(LogLevel::DEBUG) << "hello file";
ENABLE_CONSOLE_LOG();
LOG(LogLevel::DEBUG) << "hello world";
LOG(LogLevel::DEBUG) << "hello world";
LOG(LogLevel::DEBUG) << "hello world";
LOG(LogLevel::DEBUG) << "hello world";
return 0;
}
ThreadPool
threadpool.hpp
#pragma once
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{
using namespace LogMudule;
using namespace ThreadModule;
using namespace LockModule;
using namespace CondModule;
// 用来做测试的线程方法
void DefaultTest()
{
while (true)
{
LOG(LogLevel::DEBUG) << "我是一个测试方法";
sleep(1);
}
}
using thread_t = std::shared_ptr<Thread>;
const static int defaultnum = 5;
template <typename T>
class ThreadPool
{
private:
bool IsEmpty() { return _taskq.empty(); }
void HandlerTask(std::string name)
{
LOG(LogLevel::INFO) << "线程: " << name << ", 进入HandlerTask的逻辑";
while (true)
{
// 1. 拿任务
T t;
{
LockGuard lockguard(_lock);
while (IsEmpty() && _isrunning)
{
_wait_num++;
_cond.Wait(_lock);
_wait_num--;
}
// 2. 任务队列为空 && 线程池退出了
if(IsEmpty() && !_isrunning)
break;
t = _taskq.front();
_taskq.pop();
}
// 2. 处理任务
t(name); // 规定,未来所有的任务处理,全部都是必须提供()方法!
}
LOG(LogLevel::INFO) << "线程: " << name << " 退出";
}
public:
ThreadPool(int num = defaultnum) : _num(num), _wait_num(0), _isrunning(false)
{
for (int i = 0; i < _num; i++)
{
_threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "对象 ... 成功";
}
}
void Equeue(T &&in)
{
LockGuard lockguard(_lock);
if(!_isrunning) return;
_taskq.push(std::move(in));
if(_wait_num > 0)
_cond.Notify();
}
void Start()
{
if(_isrunning) return;
_isrunning = true; // bug fix??
for (auto &thread_ptr : _threads)
{
LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << " ... 成功";
thread_ptr->Start();
}
}
void Wait()
{
for (auto &thread_ptr : _threads)
{
thread_ptr->Join();
LOG(LogLevel::INFO) << "回收线程" << thread_ptr->Name() << " ... 成功";
}
}
void Stop()
{
LockGuard lockguard(_lock);
if(_isrunning)
{
// 3. 不能在入任务了
_isrunning = false; // 不工作
// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了
if(_wait_num>0)
_cond.NotifyAll();
}
}
~ThreadPool()
{
}
private:
std::vector<thread_t> _threads;
int _num;
int _wait_num;
std::queue<T> _taskq; // 临界资源
Mutex _lock;
Cond _cond;
bool _isrunning;
};
}
threadpood.cc
#include "ThreadPool.hpp"
#include "Task.hpp"
#include <memory>
using namespace ThreadPoolModule;
int main()
{
ENABLE_CONSOLE_LOG();
// ENABLE_FILE_LOG();
std::unique_ptr<ThreadPool<task_t>> tp = std::make_unique<ThreadPool<task_t>>();
tp->Start();
int cnt = 10;
char c;
while (true)
{
std::cin >> c;
tp->Equeue(Push);
// cnt--;
// sleep(1);
}
tp->Stop();
sleep(3);
tp->Wait();
return 0;
}
task.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include "Log.hpp"
using namespace LogMudule;
using task_t = std::function<void(std::string name)>;
void Push(std::string name)
{
LOG(LogLevel::DEBUG) << "我是一个推送数据到服务器的一个任务, 我正在被执行" << "[" << name << "]";
}
sigThreadPool
threadpool.hpp
#pragma once
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{
using namespace LogMudule;
using namespace ThreadModule;
using namespace LockModule;
using namespace CondModule;
// 用来做测试的线程方法
void DefaultTest()
{
while (true)
{
LOG(LogLevel::DEBUG) << "我是一个测试方法";
sleep(1);
}
}
using thread_t = std::shared_ptr<Thread>;
const static int defaultnum = 5;
template <typename T>
class ThreadPool
{
private:
bool IsEmpty() { return _taskq.empty(); }
void HandlerTask(std::string name)
{
LOG(LogLevel::INFO) << "线程: " << name << ", 进入HandlerTask的逻辑";
while (true)
{
// 1. 拿任务
T t;
{
LockGuard lockguard(_lock);
while (IsEmpty() && _isrunning)
{
_wait_num++;
_cond.Wait(_lock);
_wait_num--;
}
// 2. 任务队列为空 && 线程池退出了
if (IsEmpty() && !_isrunning)
break;
t = _taskq.front();
_taskq.pop();
}
// 2. 处理任务
t(name); // 规定,未来所有的任务处理,全部都是必须提供()方法!
}
LOG(LogLevel::INFO) << "线程: " << name << " 退出";
}
ThreadPool(const ThreadPool<T> &) = delete;
ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
ThreadPool(int num = defaultnum) : _num(num), _wait_num(0), _isrunning(false)
{
for (int i = 0; i < _num; i++)
{
_threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "对象 ... 成功";
}
}
public:
static ThreadPool<T> *getInstance()
{
if(instance == NULL)
{
LockGuard lockguard(mutex);
if(instance == NULL)
{
LOG(LogLevel::INFO) << "单例首次被执行,需要加载对象...";
instance = new ThreadPool<T>();
}
}
return instance;
}
void Equeue(T &&in)
{
LockGuard lockguard(_lock);
if (!_isrunning)
return;
_taskq.push(std::move(in));
if (_wait_num > 0)
_cond.Notify();
}
void Start()
{
if (_isrunning)
return;
_isrunning = true; // bug fix??
for (auto &thread_ptr : _threads)
{
LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << " ... 成功";
thread_ptr->Start();
}
}
void Wait()
{
for (auto &thread_ptr : _threads)
{
thread_ptr->Join();
LOG(LogLevel::INFO) << "回收线程" << thread_ptr->Name() << " ... 成功";
}
}
void Stop()
{
LockGuard lockguard(_lock);
if (_isrunning)
{
// 3. 不能在入任务了
_isrunning = false; // 不工作
// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了
if (_wait_num > 0)
_cond.NotifyAll();
}
}
~ThreadPool()
{
}
private:
std::vector<thread_t> _threads;
int _num;
int _wait_num;
std::queue<T> _taskq; // 临界资源
Mutex _lock;
Cond _cond;
bool _isrunning;
static ThreadPool<T> *instance;
static Mutex mutex; //只用来保护单例
};
template<typename T>
ThreadPool<T> *ThreadPool<T>::instance = NULL;
template<typename T>
Mutex ThreadPool<T>::mutex; //只用来保护单例
}
threadpool.cc
#include "ThreadPool.hpp"
#include "Task.hpp"
#include <memory>
using namespace ThreadPoolModule;
int main()
{
ENABLE_CONSOLE_LOG();
ThreadPool<task_t>::getInstance()->Start();
char c;
int cnt = 5;
while (cnt)
{
// std::cin >> c;
ThreadPool<task_t>::getInstance()->Equeue(Push);
cnt--;
sleep(1);
}
ThreadPool<task_t>::getInstance()->Stop();
ThreadPool<task_t>::getInstance()->Wait();
// ENABLE_FILE_LOG();
// std::unique_ptr<ThreadPool<task_t>> tp = std::make_unique<ThreadPool<task_t>>();
// tp->Start();
// int cnt = 10;
// char c;
// while (true)
// {
// std::cin >> c;
// tp->Equeue(Push);
// // cnt--;
// // sleep(1);
// }
// tp->Stop();
// sleep(3);
// tp->Wait();
return 0;
}
板书笔记
几乎没有,就不展示了