[其它] Half-Sync/Half-Async 和 Leader/Follower 模式的实现代码
iunknown
2007-07-06
在 SPServer 中实现了 HSHA 和 LF 两种线程池。
目前的实现还是比较可读的,这两种线程池最主要的处理逻辑各自都被集中到了一个函数中。 先来看看 HSHA 的核心实现代码 http://spserver.googlecode.com/svn/trunk/spserver.cpp int SP_Server :: start() { ...... SP_Executor workerExecutor( mMaxThreads, "work" ); SP_Executor actExecutor( 1, "act" ); /* Start the event loop. */ while( 0 == mIsShutdown ) { event_base_loop( eventArg.getEventBase(), EVLOOP_ONCE ); for( ; NULL != eventArg.getInputResultQueue()->top(); ) { SP_Task * task = (SP_Task*)eventArg.getInputResultQueue()->pop(); workerExecutor.execute( task ); } for( ; NULL != eventArg.getOutputResultQueue()->top(); ) { SP_Message * msg = (SP_Message*)eventArg.getOutputResultQueue()->pop(); ...... actExecutor.execute( outputCompleted, arg ); } } ...... } 一些细节都被去掉了。从这段代码可以看到,HSHA 的处理流程是: 1.运行 start 函数的线程称为 event_loop 线程,负责 recv/send 。 所有的 recv/send 都在 event_base_loop 这个函数调用上完成的。 这个层就是属于异步层。 2. event_base_loop 在 recv 的时候,会调用 MsgDecoder.decode 函数, 如果 decode 返回 OK ,说明完整地读入数据了,那么就把对应的数据放入 eventArg.mInputResultQueue 里面。 在 send 的时候,如果把一个 Message 完整地发送了, 那么就把这个 Message 放入 eventArg.mOutputResultQueue。 这两个就是队列,队列里面保存的数据一般称为完成事件。 3.workerExecutor 和 actExecutor 就是同步层。 由于完成事件的处理可能会涉及很复杂的处理,可能会使用到数据库或者其他, 因此不能直接使用 event_loop 线程,而是使用线程池。 这个就是同步层。 再来看 LF 的核心代码 http://spserver.googlecode.com/svn/trunk/splfserver.cpp int SP_LFServer :: run() { ...... mThreadPool = new SP_ThreadPool( mMaxThreads ); for( int i = 0; i < mMaxThreads; i++ ) { mThreadPool->dispatch( lfHandler, this ); } ...... } void SP_LFServer :: lfHandler( void * arg ) { SP_LFServer * server = (SP_LFServer*)arg; for( ; 0 == server->mIsShutdown; ) { /* follower begin */ server->handleOneEvent(); } } void SP_LFServer :: handleOneEvent() { SP_Task * task = NULL; SP_Message * msg = NULL; /* follower wait */ pthread_mutex_lock( &mMutex ); /* follower end */ /* leader begin */ for( ; 0 == mIsShutdown && NULL == task && NULL == msg; ) { if( mEventArg->getInputResultQueue()->getLength() > 0 ) { task = (SP_Task*)mEventArg->getInputResultQueue()->pop(); } else if( mEventArg->getOutputResultQueue()->getLength() > 0 ) { msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop(); } if( NULL == task && NULL == msg ) { event_base_loop( mEventArg->getEventBase(), EVLOOP_ONCE ); } } /* leader end */ pthread_mutex_unlock( &mMutex ); /* worker begin */ if( NULL != task ) task->run(); if( NULL != msg ) mCompletionHandler->completionMessage( msg ); /* worker end */ } 在 run 函数中,启动线程池中的多个线程运行 lfHandler , 由 lfHandler 不断地运行 handleOneEvent 。 线程的角色转变在上面的注释中可以很清楚地看到。 由于这里的实现比较简单,LF 线程池的线程都是预先创建的, 并且没有实现线程池之外的线程可以加入的功能, 所以在 leader 切换为 worker,并且提升一个 follower 为 leader 的时候, 只需要用一个 mutex 就可以解决了。 |