将设计模式运用于游戏设计:将日志做成单件

在游戏程序中日志显得非常重要,例如在调试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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值