【Linux】28:封装线程,锁,条件变量,日志

目录

一、封装线程

二、封装锁

三、封装条件变量

四、封装日志


一、封装线程

cpp 复制代码
#ifndef _THREAD_H_
#define _THREAD_H_
#include <iostream>
#include <string>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <functional>
namespace ThreadModule
{
    static uint32_t number = 1;
    class Thread
    {
        using func_t = std::function<void()>;
        void EnableDetach()
        {
            std::cout << "线程被分离了" << std::endl;
            _isdetach = true;
        }
 
    public:
        Thread(func_t func)
            : _tid(0), _isdetach(false), _isrunning(false), _res(nullptr), _func(func)
        {
            _name = "thread-" + std::to_string(number++);
        }
        void Detach()
        {
            if (_isdetach) // 如果线程已经分离了,就不需要再分离了。
                return;
            if (_isrunning)
                pthread_detach(_tid);
            EnableDetach();
        }
 
        void EnableRunning()
        {
            _isrunning = true;
        }
        static void *Routine(void *args)
        {
            Thread *self = (Thread *)args;
            self->EnableRunning();
            if (self->_isdetach) // 如果线程的分离标志是true,就调用系统调用pthread_detach来将线程设置分离
                self->Detach();
            self->_func();
            return nullptr;
        }
        bool Start()
        {
            if (_isrunning)
                return false;
            int n = pthread_create(&_tid, nullptr, Routine, this);
            if (n != 0)
            {
                std::cerr << "create pthread error" << strerror(n) << std::endl;
                return false;
            }
            else
            {
                std::cout << _name << " create sucess" << std::endl;
            }
            return true;
        }
        bool Stop()
        {
            if (_isrunning)
            {
                int n = pthread_cancel(_tid);
                if (n != 0)
                {
                    std::cerr << "cancel pthread error" << strerror(n) << std::endl;
                    return false;
                }
                else
                {
                    _isrunning = false;
                    std::cerr << _name << " stop" << std::endl;
                }
            }
            return true;
        }
        bool Join()
        {
            if (_isdetach)
            {
                std::cout << "你的线程已经是分离的,不能进行join" << std::endl;
                return true;
            }
            int n = pthread_join(_tid, &_res);
            if (n != 0)
            {
                std::cerr << "join pthread error" << strerror(n) << std::endl;
                return false;
            }
            else
            {
                std::cerr << "join pthread sucess" << std::endl;
            }
            return true;
        }
        ~Thread() {}
 
    private:
        pthread_t _tid;    // 线程id
        std::string _name; // 线程名字
        bool _isdetach;    // 是否分离,默认不分离
        bool _isrunning;   // 线程状态,是否运行
        void *_res;        // 线程返回值
        func_t _func;      // 线程执行的任务
    };
}
 
#endif

二、封装锁

cpp 复制代码
#pragma once
#include <iostream>
#include <pthread.h>
 
namespace MutexModule
{
    class Mutex
    {
    public:
        Mutex()
        {
            pthread_mutex_init(&_mutex, nullptr);
        }
        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnLock()
        {
            pthread_mutex_unlock(&_mutex);
        }
        pthread_mutex_t *Get()
        {
            return &_mutex;
        }
        ~Mutex()
        {
            pthread_mutex_destroy(&_mutex);
        }
 
    private:
        pthread_mutex_t _mutex;
    };
    class LockGuard
    {
    public:
        LockGuard(Mutex &mutex) : _mutex(mutex)
        {
            _mutex.Lock();
        }
        ~LockGuard()
        {
            _mutex.UnLock();
        }
 
    private:
        Mutex &_mutex;
    };
}

三、封装条件变量

cpp 复制代码
#pragma once
 
#include <iostream>
#include <pthread.h>
#include "Mutex.hpp"
using namespace MutexModule;
 
namespace CondModule
{
    class Cond
    {
    public:
        Cond()
        {
            pthread_cond_init(&_cond, nullptr);
        }
        void Wait(Mutex &mutex)
        {
            pthread_cond_wait(&_cond, mutex.Get());
        }
        void Singal()
        {
            pthread_cond_signal(&_cond);
        }
        void BroadCast()
        {
            pthread_cond_broadcast(&_cond);
        }
        ~Cond()
        {
            pthread_cond_destroy(&_cond);
        }
 
    private:
        pthread_cond_t _cond;
    };
}

四、封装日志

cpp 复制代码
#ifndef __LOG_HPP
#define __LOG_HPP
#include <iostream>
#include <filesystem>
#include <string>
#include <memory>
#include <unistd.h>
#include <fstream>
#include <ctime>
#include <cstdio>
#include "Mutex.hpp"
 
namespace LogModule
{
    using namespace MutexModule;
    const std::string gsep = "\r\n";
    // 刷新策略基类
    class LogStrategy
    {
    public:
        ~LogStrategy() = default;
        virtual void SyncLog(const std::string &message) = 0;
    };
    // 显示器打印日志的策略
    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        ConsoleLogStrategy() {}
        ~ConsoleLogStrategy() {}
        void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            std::cout << message << gsep;
        }
 
    private:
        Mutex _mutex;
    };
    // 文件打印日志的策略
    const std::string defaultpath = "./log";
    const std::string defaultfile = "my.log";
 
    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile)
            : _path(path),
              _file(file)
        {
            LockGuard lockguard(_mutex);
            // 来判断文件路径是否存在
            if (std::filesystem::exists(_path))
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_path);
            }
            catch (const std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << "\n";
            }
        }
 
        void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;
            std::ofstream out(filename, std::ios::app);
            if (!out.is_open())
            {
                return;
            }
            out << message << gsep;
            out.close();
        }
        ~FileLogStrategy() {}
 
    private:
        std::string _path; // 日志文件所在路径
        std::string _file; // 日志文件本身
        Mutex _mutex;
    };
 
    // 1:形成日志等级
    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    std::string Level2Str(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 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;
    }
    // 1:形成日志 2根据不同的策略,完成刷新
    class Logger
    {
    public:
        Logger()
        {
            EnableConsoleLogStrategy();
        }
        void EnableFileLogStrategy()
        {
            _fflush_strategy = std::make_unique<FileLogStrategy>();
        }
        void EnableConsoleLogStrategy()
        {
            _fflush_strategy = std::make_unique<ConsoleLogStrategy>();
        }
 
        // 内部类,表示的是未来的一条日志
        class logMessage
        {
        public:
            logMessage(LogLevel &level, std::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)
            {
                // 日志的左半部分拼进来
                std::stringstream ss;
                ss << "[" << _curr_time << "]"
                   << "[" << Level2Str(_level) << "]"
                   << "[" << _pid << "]"
                   << "[" << _src_name << "]"
                   << "[" << _line_number << "]"
                   << "-";
                _loginfo = ss.str();
            }
 
            template <typename T>
            logMessage &operator<<(const T &info)
            {
                std::stringstream ss;
                ss << info;
                _loginfo += ss.str();
                return *this;
            }
            ~logMessage()
            {
                if (_logger._fflush_strategy)
                {
                    _logger._fflush_strategy->SyncLog(_loginfo);
                }
            }
 
        private:
            std::string _curr_time;
            LogLevel _level;
            pid_t _pid;
            std::string _src_name;
            int _line_number;
            std::string _loginfo; // 合并之后一条完整的信息
 
            Logger &_logger;
        };
 
        logMessage operator()(LogLevel level, std::string name, int line)
        {
            return logMessage(level, name, line, *this);
        }
        ~Logger() {}
 
    private:
        std::unique_ptr<LogStrategy> _fflush_strategy;
    };
 
    // 定义全局日志对象
    Logger logger;
 
// 使用宏,简化用户操作
#define LOG(level) logger(level, __FILE__, __LINE__)
#define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()
#define Enable_File_Log_Strategy() logger.EnableFileLogStrategy()
}
 
#endif
相关推荐
笨笨饿1 小时前
# 59_CSDN博客自动写流程文章
linux·jvm·stm32·单片机·嵌入式硬件·mcu·51单片机
味悲1 小时前
Nginx笔记
linux·运维·笔记·nginx
Escalating_xu1 小时前
【Linux 网络编程】传输层协议 UDP:从 8 字节首部到消息边界、缓冲区与 MTU
linux·网络·udp
Lucky_Turtle1 小时前
【Linux】ip命令,路由表相关配置
linux·运维·tcp/ip
dawnsky.liu2 小时前
在 RHEL 中使用 goose 实现主机运维
linux·运维·aiops
碧海银沙音频科技研究院2 小时前
基于炬芯ATS308X的BLE 无线方式离线日志传输导出功能实现
java·linux·服务器
kkkkkkkkkk_Z2 小时前
新手自学嵌入式 | 学习日记: Linux驱动进阶 —— Platform总线与I2C子系统实战
linux·运维·学习
Android系统攻城狮2 小时前
Linux Gstreamer深度解析之gst_audio_aggregator_set_sink_caps调用流程与实战(九十一)
linux·运维·服务器·gstreamer音视频·音视频进阶
‎ദ്ദിᵔ.˛.ᵔ₎2 小时前
Linux线程:this指针在pthread中的解决方案
linux