基于ACE的定时器队列实现

    定时器MMO中的作用不需要做过多的强调,对于大多数的游戏项目来说,都是按照linux内核定时器的原理自己实现的实时器队列,详细的技术描述可以见这里,已有高人将其翻译成了中文:http://www.linuxforum.net/forum/showthreaded.php?Cat=&Board=driver&Number=385224&page=0&view=collapsed&sb=5&o=all&vc=1

 

    虽然原理并不复杂,并且有linux的内核代码可直接拿来做参考,但编码测试仍会费上一点时间,并且还会涉及到效率、稳定性、移植性等各方面的问题,而且当我们只是想在平时学习用的测试代码中用上点定时器时,这个实现的代价还是有点高了,所以,这里便有了个尝试,把ACE中提供的几个定时器队列拿出来,接口重新做下封装,以符合我们大多数人平时的使用习惯。这样一个定时器队列组件的实现不会太复杂,效率也不会太差,一点点封装代码所能引起的BUG机会也会少很多。

 

    那就进入正题吧。

 

    ACE将定时器队列分成了三大部件:分派器Dispatcher,驱动器Driver和节点容器TimerQueue。分派器用来登记和取消事件处理器,驱动器用来发出“超时事件指示”,而节点容器封装了不同算法实现的定时器队列,用来快速插入和排序登记的事件处理器。

 

    这样的划分初看起来会有些繁琐,但理解了其划分的原则之后觉得也还不错,并且ACE内置了多种不同的驱动器和节点容器实现,可以任意进行搭配以适合自己的应用需求,相对来说还是比较灵活的。

 

    AGP第20章有个演示Dispatcher、Driver与TimerQueue如何协作的例子,能够很好的说明定时器队列是如何工作的,代码就不引述了,只是实际的工程项目中面要做一点小小的修改:我们不能让程序一直wait_for_event,因为还会有其它同样重要的事要做。一个合理的方法是,让wait_for_event不再做循环处理,并且不需要等待,只处理当前已到期的定时器,整个定时器的驱动由应用的主循环来完成。

 

    或者是利用ACE提供的主动定时器,即在另一个线程中来循环等待事件的到达,只是该定时器的回调与注册不在同一个线程中处理,这将会引入多线程同步的麻烦。

 

    还有一点,希望我们的接口不光在使用上看起来与以前使用的定时器组件相似,并且从接口中也不要看到依赖于ACE的地方,这个需求应该是能够被理解的。

 

    最终的接口看起来大概会是这样的:

 

class TimerList
{
public:
 virtual ~TimerList() {}

 virtual long addTimer(TimerCallback* cb, long interval) = 0;

 virtual void removeTimer(long id) = 0;

 virtual void handleEvent() = 0;
};

 

    addTimer与removeTimer你也可能会叫它setTimer与killTimer。没错,就是MFC中的叫法。

 

    而定时器回调接口看起来会像是这样:


class TimerCallback
{
public:
 virtual void onTimer(long id) = 0;
};

 

    也许你早已将这古老的纯虚接口派生的方法丢到了垃圾桶,换上了最新最酷的boost.functor,嗯,没错,这确实有些太古老,不过,这不是因为用的人多嘛。

 

    我们再用一个TimerListImpl来实现TimerList这个接口,这个实现类中就包含了ACE的引用。因为接口不想使用ACE的EventHandler,所以我们也需要参照之前提到的那个例子,定义自己的Upcall,具体方法为:

 

typedef ACE_Timer_Queue_T<TimerCbProxy*, UpcallHandler, ACE_Null_Mutex> PTimerQueue;
typedef ACE_Timer_Heap_T<TimerCbProxy*, UpcallHandler, ACE_Null_Mutex> PTimerHeap;

 

    与例子中一样,我们只定义了使用Heap实现的定时器队列,其他算法实现的队列可按照类似的方法来定义。

 

    你可能已经注意到了,上面的类型定义中用的TimerCbProxy,而并不是之前我们定义的TimerCallback,这是因为我们想要在回调的时候传回定时器ID。为了实现这一目标,我们需要定义一个代理回调类,并在这个类中记录下该回调对应的定时器ID,这个代理就是TimerCbProxy。

 

    最终的结果看起来会是这样:

 

TimerList --> TimerListImpl --> (ACE)Timer_Quque_T --> UpcallHandler --> TimerCbProxy --> TimerCallback

 

 

    具体的实现代码还没有整理,先就不贴上来了。

 

 

 

    今天Update了下好久没关注的mangos,dep目录下添加了ACE_Wrapper。


    好情况,其实之前我就尝试过把mangos的网络部分改为使用ACE,不过做了一点之后又没再继续了,唉,还是懒!

你可能感兴趣的:(多线程,timer,算法,Class,wrapper,linux内核)