单例模式+多线程日志类
程序思路
想自己写一个日志类来记录一些日志信息、该日志类需要支持多线程。为了避免出现多个线程写日志文件的情况*(多个线程写文件、需要频繁加锁、解锁、写文件)*决定使用“队列”来解决多个线程写文件的问题,即多个线程往日志信息队列中放信息、一个real写文件线程负责从队列头取日志并写入文件。
主要问题和解决思路:
1、提供给使用者的接口、即使用者调用哪个函数来实现日志的记录。
2、负责写日志信息的函数(线程Dolog)。
该线程应该是在创建日志对象时就创建、这就需要对象构造时创建Dolog
线程。
3、如何保证日志类只有一个实例?单例模式相关文章都有讲解。
疑问
1、在测试代码中、注释掉system(“pause”);后、主线程在子线程完成之前结束、导致日志记录不全。这种情况改怎么解决?即怎么让日志对象知道主线程将要结束、从而让写日志线程退出(发消息?信号量)?
2、在debug时、发现程序并没有进入Logger的析构函数(不是说程序在退出时会自动进行资源的回收、自动调用相关对象的析构函数吗)?想知道为什么会没有进入析构函数?如果没有进入析构函数、那么怎么对资源进行回收?
完整代码
头文件 Logger.h
。
#pragma once
#include <queue>
#include <string>
#include <fstream>
#include <mutex>
using namespace std;
class Logger
{
public:
static Logger* GetInstance(){
if (instance==nullptr){
lock_guard<mutex> lk(instanceLock);//小粒度加锁
if (instance==nullptr){
instance = new Logger();
}
}
return instance;
}
static void DoLog(void* param);
void AddLog(string &log);
~Logger(void);
private:
Logger(void); //禁止在外面创建对象
Logger(Logger& logger);
static Logger *instance;
static mutex instanceLock;
mutex queueLock;
queue<string> m_log_queue;
bool m_bExit;
std::fstream m_logfs; //只有一个线程操作
};
实现文件 Logger.cpp
。
#include "Logger.h"
#include <thread>
#include <iostream>
#include <fstream>
#include <mutex>
Logger* Logger::instance = NULL;
mutex Logger::instanceLock;
Logger::Logger(void){//创建一个从queue中读数据 并写入日志文件的线程
m_bExit = false;
(this->m_logfs).open("log.txt", std::fstream::in | std::fstream::out | std::fstream::app);
thread t(Logger::DoLog, this);
t.detach();
}
void Logger::DoLog(void* param){
Logger *pThis = static_cast<Logger*>(param);
while (true){
if (!pThis->m_bExit){
unique_lock<mutex> lk(pThis->queueLock);
if (!(pThis->m_log_queue).empty()){
string log = pThis->m_log_queue.front();
pThis->m_log_queue.pop();
pThis->m_logfs << log << endl;
cout << log << endl;
}else{
}
}else
break;
}
}
void Logger::AddLog(string &log){
unique_lock<mutex> lk(queueLock);
m_log_queue.push(log);
}
Logger::~Logger(void)
{
if (Logger::instance!=NULL){
m_bExit = true;
m_logfs.close();
delete Logger::instance;
Logger::instance = NULL;
}
}
测试代码
int main()
{
clock_t start, end;
start = clock();
for (int index=0; index<9000; index++){
thread t(addlog, index);
t.join();
}
end = clock();
system("pause");//注释掉这一句 主线程在子线程之前就退出了
return 0;
}
运行结果
在查找多线程单例模式的相关资料时、有的资料说双重锁机制在C++下无效、先记录下链接供后续学习https://blog.youkuaiyun.com/linlin003/article/details/79012416