只启动了一个线程 用来写日志.
性能方面没问题, 支持多线程写入.
每3秒自动查看缓冲区是否有数据,有就写入 .或者外部N个线程同时写满一块缓冲区,进行写入.
主要是减少少量数据[几个字节]就写入一次的次数.
写入方面可以用 WriteFile 或者 _fwrite_nolock. 如果用用 WriteFile 还可以使用APC来通知,目前没此需求
另外,写入出错方面,只是简单的打印,可自行修改的完善一些
如果没有别的需求,直接使用Log类即可
Log : start() 启动, stop() 停止 ,append() 写入日志 就3个函数;
-----------------------------------------------------------------------------------------
LogBuffer : Log 用于存放日志的缓冲区
FileWriter : Log 用于创建文件,写文件
FileObject : FileWriter 用来真正写入文件的, 封装了文件指针
一个cpp 文件:
#include <Windows.h>
#include <iostream>
#include <functional>
#include <process.h>
#include <vector>
#include <memory>
#include <string>
#include <atomic>
#include <assert.h>
#include <time.h>
__thread char szErrorBuffer[MAX_PATH] = {0};
class FileObject{
public:
enum Enum_WriteBuffer { WriteBufferSize = 64 * 1024};
FileObject(const std::string & filename)
: __fp(fopen(filename.c_str(),"a+")),
__iError(0)
{
assert(NULL != __fp);
setbuf(__fp,__szBuffer);
}
~FileObject() {
::fclose(__fp);
}
void printError() {
strerror_s(szErrorBuffer,sizeof(szErrorBuffer),__iError);
std::cout << szErrorBuffer << std::endl;
}
bool Write(const char * data, const size_t & iLen) {
if(0 != __iError)
return false;
int iLeft = iLen;
int iPos = 0;
int iRet = 0;
bool bError = false;
while(iLeft > 0){
iRet = ::_fwrite_nolock(data + iPos,sizeof(char) ,iLeft,__fp); // WriteFile
if(ferror(__fp) != 0){
__iError = errno;
bError = true;
break;
}
iLeft -= iRet;
iPos += iRet;
}
if(bError){
printError();
return false;
}
return true;
}
void flush() {
::fflush(__fp);
}
const unsigned __int64 WriteBytes() const { return __iWriteBytes;}
bool isOpen() const { return 0 == __iError && __fp != NULL;}
private:
FILE *__fp;
char __szBuffer[WriteBufferSize];
unsigned __int64 __iWriteBytes;
int __iError;
};
class FileWriter{
public:
FileWriter(const std::string & filename,const unsigned __int64 & iMaxFileSize):
__filename(filename),
__iMaxFileSize(iMaxFileSize),
__pid(GetCurrentProcessId()),
__iOneDaySeconds(3600 * 24)
{
createNewFile();
}
void append(const char * data , const size_t & iLen) {
__fileobject->Write(data,iLen);
if(needCreateNewFile())
createNewFile();
}
bool needCreateNewFile() const {
__time64_t iNowDaySeconds = _time64(0) / __iOneDaySeconds * __iOneDaySeconds;
if(!__fileobject || __fileobject->WriteBytes() > __iMaxFileSize || __iCreateFileSecondsOfDay != iNowDaySeconds)
return true;
return false;
}
bool createNewFile() {
std::string filename;
__time64_t iCreateFileSeconds = getFormatFileName(filename);
__iCreateFileSecondsOfDay = (iCreateFileSeconds / __iOneDaySeconds * __iOneDaySeconds );
__fileobject.reset( new FileObject(filename) );
return (bool)__fileobject;
}
__time64_t getFormatFileName(std::string & outFileName) {
__time64_t iNow = _time64(0);
struct tm tm = { 0 };
_localtime64_s(&tm,&iNow);
char szBuffer[MAX_PATH] = {0};
sprintf_s(szBuffer,sizeof(szBuffer) , "%s_%04d%02d%02d %02d.%02d.%02d_%d.log",
__filename.c_str(),tm.tm_year+1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,__pid);
outFileName = szBuffer;
return iNow;
}
const unsigned __int64 __iMaxFileSize;
const unsigned __int64 __iOneDaySeconds;
const std::string __filename;
__time64_t __iCreateFileSecondsOfDay;
DWORD __pid;
std::unique_ptr<FileObject> __fileobject;
};
class LogBuffer{
public:
enum EnumLogFileBuffSize{enum_LogFileBuffSize = 4096 * 1024};
LogBuffer():
__start(__szBuffer)
{}
size_t leftSize() const {
return (__szBuffer + sizeof(__szBuffer)) - __start;
}
const char * data() { return __szBuffer;}
size_t dataLen() const {
return __start - __szBuffer;
}
void reset() {__start = __szBuffer;}
bool append(const char * data , const size_t & iLen){
if(leftSize() >= iLen){
memcpy(__start, data, iLen);
__start += iLen;
return true;
}
return false;
}
char * __start;
char __szBuffer[enum_LogFileBuffSize];
};
class Log{
public:
Log(const std::string & filename, const unsigned int & iAutoFlushTimeout):
__filename(filename),
__curBuffer(new LogBuffer),
__backupBuffer(new LogBuffer),
__bClose(false),
__iTimeout(iAutoFlushTimeout),
__tid(0)
{
__bStart = false;
InitializeCriticalSectionAndSpinCount(&__cs, 4000);
InitializeConditionVariable(&__cond);
}
~Log(){
stop();
DeleteCriticalSection(&__cs);
}
void stop() {
if(!__bStart)
return;
__bStart = false;
EnterCriticalSection(&__cs);
__bClose = true;
LeaveCriticalSection(&__cs);
WakeConditionVariable(&__cond);
}
bool start() {
if(__bStart)
return false;
__bClose = false;
__bStart = true;
__hThread = (HANDLE)_beginthreadex(0,0,&Log::thread_func,this,0,&__tid);
return true;
}
static unsigned int __stdcall thread_func(void * arg){
Log * log = (Log*)arg;
log->run(log);
return 0;
}
void append(const char * data, const size_t & iLen) {
if(!__bStart)
return;
EnterCriticalSection(&__cs);
if(__curBuffer->leftSize() >= iLen){
__curBuffer->append(data, iLen);
}
else{
__vcWriteBuffer.push_back(std::move(__curBuffer));
if(__backupBuffer)
__curBuffer = std::move(__backupBuffer);
else
__curBuffer.reset(new LogBuffer);
__curBuffer->append(data,iLen);
WakeConditionVariable(&__cond);
}
LeaveCriticalSection(&__cs);
}
void run(void * arg){
std::unique_ptr<LogBuffer> swapForCurBuffer ( new LogBuffer);
std::unique_ptr<LogBuffer> swapForBackupBuffer ( new LogBuffer);
std::vector<std::unique_ptr<LogBuffer>> vcLogs;
std::vector<std::unique_ptr<LogBuffer>>::iterator iter_vcLog;
FileWriter fileWrite(__filename,1024 * 1024 * 1024);
DWORD iAutoWakeupTimeout = __iTimeout * 1000;
bool bEmpty = false;
while(1) {
EnterCriticalSection(&__cs);
bEmpty = __vcWriteBuffer.empty();
if(bEmpty)
SleepConditionVariableCS(&__cond,&__cs,iAutoWakeupTimeout);
if(bEmpty && 0 == __curBuffer->dataLen() ){
LeaveCriticalSection(&__cs);
continue;
}
vcLogs.swap(__vcWriteBuffer);
vcLogs.push_back(std::move(__curBuffer));
__curBuffer = std::move(swapForCurBuffer);
if(!__backupBuffer)
__backupBuffer = std::move(swapForBackupBuffer);
LeaveCriticalSection(&__cs);
for(iter_vcLog = vcLogs.begin() ; iter_vcLog != vcLogs.end() ; ++iter_vcLog){
fileWrite.append((*iter_vcLog)->data(), (*iter_vcLog)->dataLen());
}
if(!swapForCurBuffer){
swapForCurBuffer = std::move(vcLogs.back());
vcLogs.pop_back();
swapForCurBuffer->reset();
}
if(!swapForBackupBuffer){
swapForBackupBuffer = std::move(vcLogs.back());
vcLogs.pop_back();
swapForBackupBuffer->reset();
}
if(vcLogs.size() > 2)
vcLogs.resize(2);
vcLogs.clear();
}
}
private:
std::string __filename;
std::unique_ptr<LogBuffer> __curBuffer;
std::unique_ptr<LogBuffer> __backupBuffer;
std::vector<std::unique_ptr<LogBuffer>> __vcWriteBuffer;
HANDLE __hThread;
unsigned int __tid;
unsigned int __iTimeout;
std::atomic_bool __bStart;
bool __bClose;
CRITICAL_SECTION __cs;
CONDITION_VARIABLE __cond;
};
int main(int argc, char *argv[])
{
Log log("fucklog", 3);
log.start();
//append ... append ...
while(1)
Sleep(10000);
return 0;
}
版权声明:本文为dashoumeixi原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。