之前的文章讲过,我设计的网络框架有几组线程,分别是io、异步、同步、定时器,各个不同应用server几组线程组合形式不尽相同,简单的可只有io线程,复杂一点的可io+同步,更复杂一点的也可io+同步+异步+定时器,总之我以几组线程的自由组合方式应付各种应用,在我负责的server全是这一套框架实现的,不管是支持几万人连接的服务器,还是只有几个用户连接的内部服务器,这套框架也算是久经考验,稳定运行多年,内部使用也非常简单,如给sync线程组发一个消息只要PostSyncEvent,如果要给异步线程发一个消息只要发PostAsyncEvent,虽然只能开发的时候确定哪个任务在哪组线程执行,但修改还是非常方便的,执行体就是一组这样的函数:
OnSyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
OnAsyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
一眼就知道是在哪个线程组里面执行,当然有的线程组是一个线程,有的线程组是多个,这涉及到有的资源是不是要加锁,有经验的开发人员很容易理解。
说了一下框架才容易理解我的问题,之前定时器是一个独立的线程组,同步线程组、异步线程组、io组都没有定时器功能,定时器触发后要发送消息到相应线程组,有的要发给异步线程组,有的要发给同步线程组,这就会引起线程切换,这是问题之一,还有一个问题,之前的定时器是由windows的时钟队列实现的,这个定时器优点是很明显的,定时精确,功能强大,参数众多,独立线程组,但也有很明显的问题,如果要删除一个定时器则有线程依赖,就是要在定时器线程才能删除定时器,这个依赖约束很大,也很容易引起问题,用起来很不方便,使得一些资源的释放不能够即时进行。正因为有这么些问题,也为了使得时钟模块更容易移植,我设计了一个新时钟模块,为实现以下目标:
1、无线程依赖,随便调用者在哪个线程调用都可删除指定的定时器。
2、和事件消息集成在一个线程内,实现无需切换的定时器功能,这样主线程、同步线程组、异步线程组都可在内部处理定时器消息,无需单独的定时器线程辅助,方便很多。
为实现以上目标,我引入了libevent里面的minheap管理定时器,并根据之前管理事件的处理办法,继续使用iocp队列管理线程消息,在每个线程组用iocp管理事件,根据最短触发的定时器计算wait时间,这样就在同一组线程内实现了定时器和事件合并处理,当然实现方法有很多,也可用iocp+WaitableTimer等,也可用apc,但那些实现的windows烙印都太深刻,虽然精度更高,实现更容易,我用minheap+iocp队列方式的实现相对来说对windows的依赖较少,因为替换一个iocp队列处理事件是很容易的,这样也方便移植和复用代码。经这样修改之后,各个线程组包括主线程都可处理定时器和事件消息,也使得以前鸡肋式的主线程终于可当同步线程发挥作用,以前的定时器线程组也不一定需要了,既减少了线程,也减少了切换,现在各个线程组(包括主线程)都有完全一致的消息处理和时钟处理函数。
事件函数:
OnTimerEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
OnSyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
OnAsyncEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
OnServiceEvent(DWORD dwEvent, DWORD wParam, DWORD lParam);
定时器函数:
OnTimerTimer(TlsInfo *ptls, EventTimer *et);
OnSyncTimer(TlsInfo *ptls, EventTimer *et);
OnAsyncTimer(TlsInfo *ptls, EventTimer *et);
OnIoTimer(TlsInfo *ptls, EventTimer *et);
OnServiceTimer(TlsInfo *ptls, EventTimer *et);
可以给线程组增加定时器删除定时器
AddTimer、AddSyncTimer、AddAsyncTimer、AddServiceTimer、AddIoTimer
DelTimer、DelSyncTimer、DelAsyncTimer、DelServiceTimer、DelIoTimer
可给各线程组发消息
PostTimerEvent、PostSyncEvent、PostAsyncEvent、PostServiceEvent
这套框架是我多年服务器端开发的得意之作,体现了我简洁实用的设计思想,用起来非常方便,可任意组合,适应各种需求的应用,由于除主线程之外的io线程组、同步线程组、异步线程组、定时器线程都是可以关、开1个、开多个,所以组合非常灵活,开1个可当同步线程,开多个可当异步线程(内部抢资源),关闭就不存在该组线程,即使是io线程组也是可关的,这样就使得这套框架不仅仅用在标准server上,就算是当作一般的消息队列服务器也没问题,高度的灵活性使得这套框架可适应各种规模的应用,这次对定时器的改造使得这种组合更灵活,虽然现在的实现方法定时器的精度有一些下降,但瑕不掩瑜,这样改造之后功能无疑是更强大了。