Half-Sync/Half-Async 和 Leader/Follower 模式的实现代码

把之前发表过的一篇文章贴到自己 blog 中,便于查看。

在 [url=http://code.google.com/p/spserver/]SPServer[/url] 中实现了 HSHA 和 LF 两种线程池。

目前的实现还是比较可读的,这两种线程池最主要的处理逻辑各自都被集中到了一个函数中。

先来看看 HSHA 的核心实现代码

[url]http://spserver.googlecode.com/svn/trunk/spserver.cpp[/url]

[code]
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 );
}
}

......
}
[/code]

一些细节都被去掉了。从这段代码可以看到,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 的核心代码

[url]http://spserver.googlecode.com/svn/trunk/splfserver.cpp[/url]

[code]
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 */
}
[/code]

在 run 函数中,启动线程池中的多个线程运行 lfHandler ,
由 lfHandler 不断地运行 handleOneEvent 。
线程的角色转变在上面的注释中可以很清楚地看到。

由于这里的实现比较简单,LF 线程池的线程都是预先创建的,
并且没有实现线程池之外的线程可以加入的功能,
所以在 leader 切换为 worker,并且提升一个 follower 为 leader 的时候,
只需要用一个 mutex 就可以解决了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值