Ogre 源码分析之 LogManager

Ogre LogManager 分析

 

设计上从名字就可以推断出来LogManager使用了单例模式,这样为LogManager的全局访问提供了非常大的帮助。

下面是LogManager的继承结构:

 

            

 

继承结构:

 

Ogre::Singleton<LogManager>

 

我们之前有对OgreSingleton模式进行过分析,这里不再赘述。详见 Ogre 设计模式之Singleton

 

LogAlloc

 

本来我想把LogAlloc附带分析了,但是分析代码的过程中,发现其内部的复杂度已经超过我目前的C++和多线程的理解水平,所以未来抽时间单独的把LogAlloc分析一下。

 

现在先把LogAlloc概述一下,希望大牛们看到这篇文章可以指点一二。

 

LogAllocGeneralAllocatedObject的别名,而GeneralAllocatedObject 是 AllocatedObject的一种通用分配策略(GeneralAllocPolicy),这种采基于Policy的设计,在 Modern C++ Design 里面有详细的讲解。

 

AllocatedObject 中重载了 new , new[], delete , delete[] 等诸多方法,我们会看到new的很多重载版本,我们这里讲解一个: 

 

void* operator new[] ( size_t sz, const char* file, int line, const char* func )

{

return Alloc::allocateBytes(sz, file, line, func);

}

 

讲到这里不得不先提一下Ogre LogManager的初始化方式,如下:

 

mLogManager = OGRE_NEW LogManager();

mLogManager->createLog(logFileName, true, true);

 

 

OgreOGRE_NEW 宏,如下:

 

# define OGRE_NEW new (__FILE__, __LINE__, __FUNCTION__)

 

 

OGRE_NEW 的 __FILE__, __LINE__, __FUNCTION__ (这三个参数是编译器内部定义的宏,记录出错的文件,行和函数三个参数在 调用 OGRE_NEW  XXX[] 时传入 operator new

 

这样做的目的是可以为了定位错误所用,当new失败的时候,需要throw的时候,Ogre会把抛出的错误,以写入日志或以弹出窗口的方式来告知用户。

 

参数是Alloc是模板参数,这里的具体参数是 GeneralAllocPolicy ,它是CategorisedAllocPolicy<Ogre::MEMCATEGORY_GENERAL> 的别名,而 CategorisedAllocPolicy 定义如下:

 

template <MemoryCategory Cat> class CategorisedAllocPolicy : public NedPoolingPolicy{};

 

继承的基类 NedPoolingPolicy 采用了 nedmalloc 的方式,它是多线程的,带锁,其实nedmalloc 也是线程缓存式的内存池。nedmalloc 的确没有看懂,希望大牛指点一二。

这里的模板参数要注意,它是enum类型的,指示需要制定的内存分配策略。

好了 LogAlloc 就介绍到这里,关于Ogre的内存分配,我会以后花时间详细分析一下。

 

LogManager的成员和方法:

 

回到LogManager的主题(囧 不知不觉感觉刚才有点跑题)LogManager有很多辅助方法如 getter/setter ,这种不再赘述,重点讲解一下LogManager的以下三种方法:

 

1. Log* createLog();

 

2. void destroyLog();

 

3.  void logMessage();

 

1. createLog()  方法:

 

Log* LogManager::createLog( const String& name, bool defaultLog, bool debuggerOutput, 

bool suppressFileOutput)

{

    OGRE_LOCK_AUTO_MUTEX

 

        Log* newLog = OGRE_NEW Log(name, debuggerOutput, suppressFileOutput);

 

        if( !mDefaultLog || defaultLog )

        {

            mDefaultLog = newLog;

        }

 

        mLogs.insert( LogList::value_type( name, newLog ) );

 

        return newLog;

 } 

LogManager中的方法几乎都要加锁,createLog也不例外。这里使用了Ogre使用了Ogre独特的加锁方式,这种加锁方式很好的避免了重入和加锁之后忘记解锁的缺点。内部的实现已经类似于局部的类,开始的时候构造加锁,最后离开函数析构解锁。

 

因为可以Ogre允许创建多个log(默认只有一个),创建之后插入mLogs,它是一个LogList,LogList的定义如下:

 

typedef map<String, Log*>::type LogList;

 

使用map的原因在于想把keyvalue对应起来,这个用处在 destroy() 方法中将会有体现。最后这个方法新创建的Log指针。

 

2. void destroyLog(); 方法

 

destroyLog() 重载了两种方式,第一种是通过string,另一种是通过Log指针。但是第二种是通过获得Log指针的name,来调用第一种,所以本质上说是一种方法。

 

  void LogManager::destroyLog(const String& name)
    {
        LogList::iterator i = mLogs.find(name);
        if (i != mLogs.end())
        {
            if (mDefaultLog == i->second)
            {
                mDefaultLog = 0;
            }
            OGRE_DELETE i->second;
            mLogs.erase(i);
        }

        // Set another default log if this one removed
        if (!mDefaultLog && !mLogs.empty())
        {
            mDefaultLog = mLogs.begin()->second;
        }
    } 

简单明了,查找和字符串相同名字的log,然后用OGRE_DELETE删除掉,如果是删除当前默认的Log,那么选择删除后map的第一个作为默认的log

 

3.  void logMessage(); 方法

 

这个是LogManager里面最重要的方法,方法中调用了mLog成员变量的logMessage

方法,这样做主要是把log的具体实现,主要是文件操作,和manager分离开来,达到manager是独立的效果。

 

在这个方法中需要注意的有以下三点:

 

A) 关于log报告的等级,如下代码将会根据你需要的等级对log进行写入。

 

       if ((mLogLevel + lml) >= OGRE_LOG_THRESHOLD)

 

B) 这里log的实现使用了观察者模式,如果需要监听log 就需要继承 LogListener,并实现抽象方法 messageLogged() ,然后调用addListner()方法把需要监听的类的指针注册进来,存放在一个vector里面,当每次需要写入log的时候,logMessage()方法就遍历vector,调用对应监听者的messageLogged() 的方法。

 

C Ogre会根据你的需要写入控制台还是file中,而且每次是即时写,即输出到对应目标,调用内嵌类的 Stream (本质是个 basic_string )的对象 mLog 的 flush() 方法。

 

好了,今天LogManager就分析到这里,下一次分析Ogre SDK 的一个例子或者 Ogre 的 DyLibManager

 

转载于:https://www.cnblogs.com/singmelody/archive/2012/11/11/2765532.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值