日志 多线程 自动刷新 _fwrite_nolock

只启动了一个线程 用来写日志. 

性能方面没问题, 支持多线程写入.

每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版权协议,转载请附上原文出处链接和本声明。