目录
一、封装线程
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