把之前发表过的一篇文章贴到自己 blog 中,便于查看。
在
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 就可以解决了。