线程池日志
最近需要写日志,我们都知道,日志这东西如果影响了主线程的执行,那么从性能上讲就得不偿失了。所以想起来了弄个线程日志。简单的,直接上代码
#include <iostream>
#include <map>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <unistd.h>
namespace log {
class TaskLog
{
std::string _fileName;
std::string _log;
public:
TaskLog() {}
void setData(const std::string& fileName, const std::string& log )
{
this->_fileName = fileName;
this->_log = log + "\n";
}
std::string fileName()
{
return this->_fileName;
}
std::string log()
{
return this->_log;
}
};
class ThreadLog
{
std::atomic<bool> _startLog;
std::thread* _thread;
std::condition_variable _condition;
std::mutex _taskQueueMutex;
std::queue<TaskLog> _taskQueue;
std::map<std::string , std::FILE*> _mapFiles;
private:
ThreadLog() :_startLog(true){
this->_thread = new std::thread(&ThreadLog::workLog,this);
sleep(1);
}
public:
static ThreadLog * getInst()
{
static ThreadLog log;
return &log;
}
~ThreadLog() {
std::cout<<" logthread is start exit \n";
this->_startLog = false;
this->_condition.notify_all();
if(this->_thread)
{
std::cout<<" logthread is exit safety \n";
this->_thread->join();
}
}
void addTask(const TaskLog& task)
{
{
std::unique_lock<std::mutex> lock(this->_taskQueueMutex);
this->_taskQueue.push(task);
}
this->_condition.notify_one();
}
void workLog()
{
while (this->_startLog) {
std::atomic<bool> isEmpty(false);
TaskLog tl;
{
std::unique_lock<std::mutex> lock(this->_taskQueueMutex);
this->_condition.wait(lock, [this] { return !this->_startLog || !this->_taskQueue.empty(); });
// if (!this->_startLog && this->_taskQueue.empty())
// return;
if(this->_taskQueue.empty())
{
isEmpty = true;
}
else
{
tl = this->_taskQueue.front();
this->_taskQueue.pop();
}
}
if(!isEmpty)
{
std::FILE * file = NULL;
auto iter = this->_mapFiles.find(tl.fileName());
if(iter != this->_mapFiles.end())
{
file = iter->second;
}
else
{
file = fopen(tl.fileName().c_str(),"a+");
if(file == NULL)
{
std::cout<<tl.fileName()<<" is open failed!\n";
}
else
{
this->_mapFiles.insert(std::make_pair(tl.fileName(),file));
}
}
fwrite(tl.log().c_str(),sizeof (char),tl.log().length(),file);
fflush(file);
}
}
for(const auto &fl : this->_mapFiles)
{
fclose(fl.second);
std::cout<<fl.first<<" file is closed safety \n";
}
// auto iterfile = this->_mapFiles.begin();
// while (iterfile != this->_mapFiles.end()) {
// fclose(iterfile->second);
// iterfile->second = NULL;
// std::cout<<iterfile->first<<" file is closed safety \n";
// iterfile++;
// }
}
};
#define LOGINFO(x) log::TaskLog taskInfo; taskInfo.setData("loginfo.log",x); log::ThreadLog::getInst()->addTask(taskInfo);
#define LOGDEBUG(x) log::TaskLog taskDebug; taskDebug.setData("logdebug.log",x); log::ThreadLog::getInst()->addTask(taskDebug);
}
void logTest()
{
for (size_t index = 0;index < 100;index++)
{
std::string str = "logs" + std::to_string(index);
LOGINFO(str);
LOGDEBUG(str);
}
}
void testlogMutiThread( int thread = 8)
{
std::vector<std::thread*> vth;
for (int i = 0; i < thread;i++)
{
std::thread * th = new std::thread(logTest);
sleep(1);
vth.push_back(th);
}
for (const auto t : vth)
{
t->join();
}
}
int main(int argc, char *argv[])
{
testlogMutiThread();
//logTest();
//sleep(100);
std::cout<<" main(int argc, char *argv[]) over \n";
return 0;
}
觉得还有的优化,所以就有了下面这个版本
#include <iostream>
#include <map>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <unistd.h>
namespace log {
class TaskLog
{
std::string _fileName;
std::string _log;
public:
TaskLog() {}
TaskLog(const std::string& fileName, const std::string& log )
{
this->_fileName = fileName;
this->_log = log + "\n";
}
void setData(const std::string& fileName, const std::string& log )
{
this->_fileName = fileName;
this->_log = log + "\n";
}
std::string fileName()
{
return this->_fileName;
}
std::string log()
{
return this->_log;
}
};
class ThreadLog
{
std::atomic<bool> _startLog;
std::thread* _thread;
std::condition_variable _condition;
std::mutex _taskQueueMutex;
std::queue<TaskLog> _taskQueue;
std::map<std::string , std::FILE*> _mapFiles;
private:
ThreadLog() :_startLog(true){
this->_thread = new std::thread(&ThreadLog::workLog,this);
sleep(1);
}
public:
static ThreadLog * getInst()
{
static ThreadLog log;
return &log;
}
~ThreadLog() {
std::cout<<" logthread is start exit \n";
this->_startLog = false;
this->_condition.notify_all();
if(this->_thread)
{
std::cout<<" logthread is exit safety \n";
this->_thread->join();
}
}
template <typename T>
using FormatFunc = std::string (*)(const T &);
template <typename T>
void addLog(FormatFunc<T> func,const T& data,const std::string& fileName)
{
this->addLog(fileName,func(data));
}
void addLog(const std::string& fileName, const std::string& log )
{
TaskLog task(fileName,log);
this->addTask(task);
}
void addTask(const TaskLog& task)
{
{
std::unique_lock<std::mutex> lock(this->_taskQueueMutex);
this->_taskQueue.push(task);
}
this->_condition.notify_one();
}
void workLog()
{
while (this->_startLog) {
std::atomic<bool> isEmpty(false);
TaskLog tl;
{
std::unique_lock<std::mutex> lock(this->_taskQueueMutex);
this->_condition.wait(lock, [this] { return !this->_startLog || !this->_taskQueue.empty(); });
// if (!this->_startLog && this->_taskQueue.empty())
// return;
if(this->_taskQueue.empty())
{
isEmpty = true;
}
else
{
tl = this->_taskQueue.front();
this->_taskQueue.pop();
}
}
if(!isEmpty)
{
std::FILE * file = NULL;
auto iter = this->_mapFiles.find(tl.fileName());
if(iter != this->_mapFiles.end())
{
file = iter->second;
}
else
{
file = fopen(tl.fileName().c_str(),"a+");
if(file == NULL)
{
std::cout<<tl.fileName()<<" is open failed!\n";
}
else
{
this->_mapFiles.insert(std::make_pair(tl.fileName(),file));
}
}
fwrite(tl.log().c_str(),sizeof (char),tl.log().length(),file);
fflush(file);
}
}
for(const auto &fl : this->_mapFiles)
{
fclose(fl.second);
std::cout<<fl.first<<" file is closed safety \n";
}
// auto iterfile = this->_mapFiles.begin();
// while (iterfile != this->_mapFiles.end()) {
// fclose(iterfile->second);
// iterfile->second = NULL;
// std::cout<<iterfile->first<<" file is closed safety \n";
// iterfile++;
// }
}
};
#define LOGINFO(x) log::ThreadLog::getInst()->addLog("loginfo.log",x);
#define LOGDEBUG(x) log::ThreadLog::getInst()->addLog("logdebug.log",x);
}
void logTest()
{
for (size_t index = 0;index < 100;index++)
{
std::string str = "logs" + std::to_string(index);
LOGINFO(str);
LOGDEBUG(str);
}
}
void testlogMutiThread( int thread = 8)
{
std::vector<std::thread*> vth;
for (int i = 0; i < thread;i++)
{
std::thread * th = new std::thread(logTest);
sleep(1);
vth.push_back(th);
}
for (const auto t : vth)
{
t->join();
}
}
int main(int argc, char *argv[])
{
testlogMutiThread();
//logTest();
//sleep(100);
std::cout<<" main(int argc, char *argv[]) over \n";
return 0;
}