[其它] 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 就可以解决了。
Global site tag (gtag.js) - Google Analytics