本篇主要介绍领导者/追随者模式
领导者/追随者模式是多个工作线程轮流获得事件源集合。轮流监听、分发并处理事件的一种模式。在任意时间点,程序都仅有一个领导者线程,它负责监听I/O事件。而其他线程则都是追随者,它们休眠在线程池中等待成为新的领导者。当前的领导者如果检测到I/O事件,首先要从线程池中推选出新的领导者线程,然后处理I/O事件。此时,新的领导者等待新的I/O事件,而原来的领导者则处理I/O事件,二者实现了并发。
领导者/追随者模式包含以下几个组件:句柄集(HandleSet)、线程集(ThreadSet)、事件处理器(EventHandle)和具体的事件处理器(ConcreteEventHandler)。它们关系如图1所示:
图 1 领导者/追随者模式的组件
1.句柄集(HandleSet)
句柄(Handle)用于表示I/O资源,在Linux下通常就是一个文件描述符。句柄集管理众多句柄,它使用wait_for_event方法来监听这些句柄上的I/O事件,并将其中的就绪事件通知给领导者线程。领导者则调用绑定到Handle上的事件处理器来处理事件。领导者将Handle和事件处理器绑定是通过句柄集中的register_handle方法实现的。
2.线程集(ThreadSet)
这个组件是所有工作线程(包括领导者和追随者线程)的管理者。它负责各线程之间的同步,以及新领导者线程的推选。线程集中的线程在任一时间必处于如下三种状态之一:
1)Leader:线程当前处于领导者身份,负责等待句柄集上的I/O事件。
2)Preocessing:线程正在处理事件。领导者检测到I/O事件后,可以转移到Preocessing状态来处理该事件,并调用promote_new_leader方法推选新的领导者;也可以指定其他追随者来处理事件(Event Handoff),此时领导者的地位不变,当处于Preocessing状态的线程处理完事件后,如果当前线程集中没有领导者,则它将成为新的领导者,否则它就直接转变为追随者。
3)Follower:线程当前处于追随者身份,通过调用线程集的join方法等待成为新的领导者,也可能被当前的量到这指定来处理新的任务。
图2显示了这三种状态之间的转换关系。
图 2 领导者/追随者模式的状态转移
3.事件处理器(EventHandle)和具体的事件处理器(ConcreteEventHandler)
事件处理器通常包含一个或多个回调函数handle_event。这些回调函数用于处理事件对应的业务逻辑。事件处理器在使用前需要被绑定到某个句柄上,当该句柄上有时间发生时,领导者就执行与之绑定的事件处理器中的回调函数。具体的事件处理器是事件处理器的派生类。它们必须重新实现基类的handle_event方法,以处理特定的任务。
根据上面的讨论,我们将领导者/追随者模式的工作流程总结于图3中。
图 3 领导者/追随者模式
由于领导者线程自己监听I/O事件并处理客户请求,因而领导者/追随者模式不需要在线程之间传递任何额外的数据,也无需像半同步/半反应堆模式那样在线程之间的同步对请求队列的访问。但领导者/追随者的一个明显缺点是仅支持一个事件源集合,因此也无法像半同步/半异步模式那样,让每个工作线程独立地管理多个客户连接。
至此,服务器程序框架总结完毕,接下来可能要准备有没有机会去实习,暑假也要找工作,更博可能要缓一缓了。