现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

应用单例模式设计日志

2015-02-21 22:58 工业·编程 ⁄ 共 2884字 ⁄ 字号 暂无评论
文章目录

在游戏程序中日志显得非常重要,例如在调试AI的时候需要连续跟踪AI状态的变化,在非正常的函数返回点记录状态信息等等。但是这一系列的log如果没有统一管理那么将变得很混乱,而且在多线程的情况下有可能会出现同步问题。为此专门用单件的模式制作了一个日志类,希望能派的上用场。不多说了,直接贴代码,原理很简单,关键地方有注释。

log.h

#include <windows.h>

#include <fstream>

class CSynObj

{

public:

    CSynObj()

    {

        InitializeCriticalSection(&m_cs);

    }

~CSynObj()

    {

        DeleteCriticalSection(&m_cs);

    }

void Lock()

   {

       EnterCriticalSection(&m_cs);   

   }

void UnLock()

   {

       LeaveCriticalSection(&m_cs);

   }

private:

    CRITICAL_SECTION m_cs;

};

class CLock       

{

public:

    CLock(CSynObj& synchobject)

        :refSynchObject(synchobject)

    {

        refSynchObject.Lock();

    }

virtual ~CLock()

    {

        refSynchObject.UnLock();

    }

protected:

    CSynObj& refSynchObject;

};

enum LOG_TARGET_E

{

    LOG_TARGET_SCREEN    = 1,

    LOG_TARGET_FILE        = 2,

};

class CLog

{

private:

~CLog();

    CLog();

    CLog(const CLog& rhs) {}

    CLog& operator = (const CLog& rhs) {}

static CLog*    m_pLog;

static CSynObj    m_Lock;

    std::ofstream    m_OutFile;

void GetSysTime(SYSTEMTIME* lpSysTime);

void FormatAllTime(const SYSTEMTIME& refSysTime, std::string& strOut);

public:

void    Write(char* pMsg, int nTarget);

static CLog*    GetInstance();

// 摧毁singleton的入口

static void DestroyInstance();

};

__inline void DEBUG_MSG(LPSTR filename, int lineno, LPSTR linedesc, DWORD dwErrCode, int nOutPutTarget = LOG_TARGET_SCREEN|LOG_TARGET_FILE)

{

char cTemp[256];

    sprintf( cTemp, "%lu error on %d line in %s file: %s", dwErrCode, lineno, filename, linedesc );

    CLog* pLog = CLog::GetInstance();

    pLog->Write( cTemp, nOutPutTarget );

}

log.cpp

#include <iostream>

#include <log.h>

CLog* CLog::m_pLog = NULL;

CSynObj    CLog::m_Lock;

CLog::~CLog()

{

    m_OutFile.close();

}

CLog::CLog()

{

    m_OutFile.open( "Log.txt", std::ios::app );

    atexit( CLog::DestroyInstance );

}

void CLog::GetSysTime(SYSTEMTIME* lpSysTime)

{

//获得系统时间

    FILETIME CurFileTime;

    ::GetSystemTimeAsFileTime(&CurFileTime);

    ::FileTimeToLocalFileTime(&CurFileTime, &CurFileTime);

    ::FileTimeToSystemTime(&CurFileTime, lpSysTime);

}

void CLog::FormatAllTime(const SYSTEMTIME& refSysTime, std::string& strOut)

{

//系统时间转换成字符串

char cBuffer[MAX_PATH*2];

    sprintf(cBuffer,"%d-%02d-%02d %02d:%02d:%02d",

        refSysTime.wYear, refSysTime.wMonth, refSysTime.wDay , refSysTime.wHour , refSysTime.wMinute , refSysTime.wSecond);

    strOut = cBuffer;

}

void CLog::Write(char* pMsg, int nTarget)

{

// 区间锁,在同一时刻只允许一个线程进行写文件或屏幕

    CLock Lock( CLog::m_Lock );

    SYSTEMTIME Systime;

    std::string strTime;

    GetSysTime( &Systime );

    FormatAllTime( Systime, strTime );

if( nTarget & LOG_TARGET_FILE )

        m_OutFile << strTime.c_str() << ": " << pMsg << std::endl;

if( nTarget & LOG_TARGET_SCREEN )

        std::cout << pMsg << std::endl;

}

CLog* CLog::GetInstance()

{

// 双次检测的好处

// 1:防止多线程同时进入new CLog;

// 2:临界区写在第二次判断,提高了效率

if( !m_pLog )

    {

        CLock Lock( CLog::m_Lock );

if( !m_pLog )

            m_pLog = new CLog;

    }

return m_pLog;

}

// 与GetInstance对应,给CLog一个delete的机会

void CLog::DestroyInstance()

{

    delete m_pLog;

    m_pLog = NULL;

}

int main()

{

    atexit( CLog::DestroyInstance );

    DEBUG_MSG( __FILE__, __LINE__, "main()", 0 );

    getchar();

return 0;

}

给我留言

留言无头像?