36 Linux线程池实战:日志与策略模式解析

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

🌟心向往之行必能至

正式实现线程池之前,我们要进行引入前面的封装,及实现日志

一.日志与策略模式

什么是设计模式
IT⾏业这么⽕, 涌⼊的⼈很多. 俗话说林⼦⼤了啥⻦都有. ⼤佬和菜鸡们两极分化的越来越严重. 为了让 菜鸡们不太拖⼤佬的后腿, 于是⼤佬们针对⼀些经典的常⻅的场景, 给定了⼀些对应的解决⽅案, 这个就是 设计模式

1.1 日志的认识

计算机中的⽇志是记录系统和软件运⾏中发⽣事件的⽂件,主要作⽤是监控运⾏状态、记录异常信
息,帮助快速定位问题并⽀持程序员进⾏问题修复。它是系统维护、故障排查和安全管理的重要⼯
具。

⽇志格式以下⼏个指标是必须得有的
• 时间戳
• ⽇志等级
• ⽇志内容
以下⼏个指标是可选的
• ⽂件名⾏号
• 进程,线程相关id信息等

bash 复制代码
[可读性很好的时间] [⽇志等级] [进程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
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [20] - hello world
[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [21] - hello world
[2024-08-04 12:27:03] [WARNING] [202938] [main.cc] [23] - hello world

文件写入:使用 ofstream

ofstream 类用于向文件写入数据。要写入文件,首先需要包含头文件 <fstream> 并创建一个 ofstream 对象。使用 open() 方法打开文件,然后通过插入运算符 << 写入数据。完成写入后,调用 close() 方法关闭文件流。

bash 复制代码
NAME
       time - run programs and summarize system resource usage

SYNOPSIS
       time   [ -apqvV ] [ -f FORMAT ] [ -o FILE ]
              [ --append ] [ --verbose ] [ --quiet ] [ --portability ]
              [ --format=FORMAT ] [ --output=FILE ] [ --version ]
              [ --help ] COMMAND [ ARGS ]

C++17 文件系统操作

C++17 引入了 std::filesystem 库,用于跨平台处理文件和目录操作,提供了路径管理、文件遍历、属性获取与修改等功能,极大简化了文件系统编程。

核心类

  • path:路径处理的基础类,封装字符串路径并提供解析、拼接等操作。

  • directory_entry:文件入口类,用于访问文件或目录的属性。

  • directory_iterator:目录迭代器,用于遍历目录内容。

  • file_status:文件状态类,用于获取文件类型、权限等信息。

示例:遍历目录与文件信息

bash 复制代码
#include <iostream>
#include <cstdio>
#include <string>
#include <filesystem> //C++17
#include <sstream>
#include <fstream>
#include <memory>
#include <ctime>
#include <unistd.h>
#include "mutex.hpp"
namespace Logmtuble
{
    using namespace Mutexmtuble;
    using namespace std;
    const std::string gsep = "\r\n";
    class LogSratery
    {
    public:
        ~LogSratery() = default;
        virtual void SyncLog(const string &messages) = 0;
    };
    class MonitorLogSratery : public LogSratery
    {
    public:
        MonitorLogSratery() {}
        void SyncLog(const std::string &messages) override
        {
            Lockguard lg(_mutex);
            cout << messages << gsep;
        }

    private:
        Mutex _mutex;
    };
    const string path = "./log";
    const string file = "my.long";
    class FileLogSratery : public LogSratery
    {
    public:
        FileLogSratery(string p = path, string f = file)
            : _path(p), _file(f)
        {
            Lockguard lg(_mutex);
            if (filesystem::exists(_path))
                return;
            try
            {
                filesystem::create_directories(_path); // 路径不'存在.就创造
            }
            catch (const filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << '\n';
            }
        }

        void SyncLog(const string &messages) override
        {
            string filename = _path + (_path.back() == '/' ? "" : "/") + _file;
            ofstream out(filename, ios::app); // 追击写入
            if (!out.is_open())
            {
                return;
            }
            out << messages << gsep;
            out.close();
        }
        ~FileLogSratery() {}

    private:
        Mutex _mutex;
        string _path; // 所在路径
        string _file; // 写入文件
    };
    // 上面可供选择不同的刷新策略与写入方式
    // 形成日志等级
    enum class LogLeval
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    string Level2Str(LogLeval level)
    {
        switch (level)
        {
        case LogLeval::DEBUG:
            return "DEBUG";
        case LogLeval::INFO:
            return "INFO";
        case LogLeval::WARNING:
            return "WARNING";
        case LogLeval::ERROR:
            return "ERROR";
        case LogLeval::FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
        }
    }
    string GetTimeStamp()
    {
        time_t curr = time(nullptr);
        struct tm curr_tm;
        localtime_r(&curr, &curr_tm);
        char timebuffer[128];
        snprintf(timebuffer, sizeof(timebuffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr_tm.tm_year + 1900,
                 curr_tm.tm_mon + 1,
                 curr_tm.tm_mday,
                 curr_tm.tm_hour,
                 curr_tm.tm_min,
                 curr_tm.tm_sec);
        return timebuffer;
    }
    class Logger
    {
    public:
        Logger()
        {
            EnableMonitorLogSratery();
        }
        void EnableMonitorLogSratery()
        {
            _fflush_strategy = make_unique<MonitorLogSratery>();
        }
        void EnalbleFileSratery()
        {
            _fflush_strategy = make_unique<FileLogSratery>();
        }
        // 表示未来的一条日志

        class LogMessage
        {
        public:
            LogMessage(LogLeval &level, string &src_name, int line_number, Logger &logger)
                : _curr_time(GetTimeStamp()),
                  _level(level),
                  _pid(getpid()),
                  _src_name(src_name),
                  _line_number(line_number),
                  _logger(logger)
            {
                stringstream ss;
                ss << "[" << _curr_time << "] "
                   << "[" << Level2Str(_level) << "] "
                   << "[" << _pid << "] "
                   << "[" << _src_name << "] "
                   << "[" << _line_number << "] "
                   << "- ";
                _loginfo = ss.str();
            }
            // LogMessage() << "hell world" << "XXXX" << 3.14 << 1234
            template <class T>
            LogMessage &operator<<(const T &info)
            {
                stringstream ss;
                ss << info;
                _loginfo += ss.str();
                return *this;
            }
            ~LogMessage()
            {
                if (_logger._fflush_strategy)
                {
                    _logger._fflush_strategy->SyncLog(_loginfo);
                }
            }

        private:
            string _curr_time;
            LogLeval _level;
            pid_t _pid;
            string _src_name;
            int _line_number;
            string _loginfo; // 一条完整的
            Logger &_logger;
        };
        // 这里故意写成返回临时对象
        LogMessage operator()(LogLeval level, string name, int line)
        {
            return LogMessage(level, name, line, *this);
        }
        ~Logger()
        {
        }

    private:
        unique_ptr<LogSratery> _fflush_strategy;
    };
    // 使用宏,简化用户操作,获取文件名和行号
#define LOG(level) logger(level, __FILE__, __LINE__)
#define Enable_File_Log_Srategy() logger.FileSratery()
#define Enable_Monitor_Log_Srategy() logger.MonitorLogSratery()

}

线程池

bash 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include "Log.hpp"
#include "cond.hpp"
#include "Thread.hpp"
using namespace Logmtuble;
using namespace Condmtuble;
using namespace Milestone;
const int gnum = 5;
template <class T>
class threadpool
{
    private:
    void WakeUpAllThread()
    {
        LockGuard lockguard(_mutex);
        if (_sleepernum)
            _cond.Broadcast();
        LOG(LogLevel::INFO) << "唤醒所有休眠线程";
    }

    void WakeUpOne()
    {
        _cond.Signal();
        LOG(LogLevel::INFO) << "唤醒一个休眠线程";
    }
    void join()
    {
        if(!_isrunning)
            return;
        for(auto&thread_threads)
        {
            thread.join();
        }
    }
    
public:
    threadpool(int num = gnum)
        : _num(num), _isrunning(false)
                         _sleeprnum(0)
    {
        for (int i = 0; i < num; i++)
        {
            _threads.emplace_back(
                [this]()
                {
                    HandlerTask();
                });
        }
    }
    void Start()
    {
        if (_isrunning)
            return;
        _isrunning = true;
        for (auto &thread : _threads)
        {
            thread.start();
            LOG(LogLevel::INFO) << "start new thread success: " << thread.Name();
        }
    }

    void HandlerTask()
    {
        char name[128];
        pthread_getname_np(pthread_self(), name, sizeof(name));
        while (true)
        {
            T t;
            {
                Lockguard lg(_mutex);
                // 1. a.队列为空 b. 线程池没有退出
                while (_taskq.empty() && _isrunning)
                {
                    _sleepernum++;
                    _cond.Wait(_mutex);
                    _sleepernum--;
                }
                // 2. 内部的线程被唤醒
                if (!_isrunning && _taskq.empty())
                {
                    LOG(LogLevel::INFO) << name << " 退出了, 线程池退出&&任务队列为空";
                    break;
                }

                // 一定有任务
                t = _taskq.front(); // 从q中获取任务,
                _taskq.pop();
            }
            t();
        }
    }
     bool Enqueue(const T &in)
        {
            if (_isrunning)
            {
                LockGuard lockguard(_mutex);
                _taskq.push(in);
                if (_threads.size() == _sleepernum)
                    WakeUpOne();
                return true;
            }
            return false;
        }
        ~ThreadPool()
        {
        }

private:
    vector<Thread> _threads;
    int _num; // 线程池的线程个数
    queue<T> _taskq;
    Cond _cond;
    Mutex _mutex;

    bool _isrunning;
    int _sleepernum;
};
相关推荐
iPadiPhone2 小时前
Java 泛型与通配符全链路解析及面试进阶
java·开发语言·后端·面试
ArturiaZ2 小时前
【day53】
开发语言·c++·算法
颜颜yan_2 小时前
从千毫秒到亚毫秒:连接条件下推如何让复杂 SQL 飞起来
数据库·sql
haiyaoyouyou2 小时前
Qt ElaWidgetTools 编译运行示例
开发语言·qt·qt creator·elaframework·mingw_64
lzp07912 小时前
python爬虫——爬取全年天气数据并做可视化分析
开发语言·爬虫·python
可编程芯片开发2 小时前
基于自适应MUSIC算法的波束形成matlab仿真
算法·matlab·波束形成·自适应music
白藏y2 小时前
【C++】特殊类设计与单例模式
c++·单例模式
会编程的土豆2 小时前
C语言实现:影院票务管理系统(铠甲怪兽管理系统)(详细解析+效果展示)C语言实现:影院票务管理系统(铠甲怪兽管理系统)(详细解析+效果展示)
c语言·开发语言·课程设计·项目·管理系统
2301_789015622 小时前
DS进阶:红黑树
c语言·开发语言·数据结构·c++·算法·r-tree·lsm-tree