分享

Reactor模式

 sun317 2014-01-22
Reactor模式翻译成中文通常学叫做“反应堆”模式,强调的是回调机制与事件。

Reactor的事件处理机制

首先来回想一下普通函数调用的机制:程序调用某函数,函数执行,程序等待,函数将结果和控制权返回给程序,程序继续处理。Reactor释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的时间发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。

Reactor模式的优点

Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:

  • 响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
  • 可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;
  • 可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;

Reactor模式框架

使用Reactor模型,必备的几个组件:事件源、Reactor框架、多路复用机制和事件处理程序,先来看看Reactor模型的整体框架,接下来再对每个组件做逐一说明。

components

 

事件源

Linux上是文件描述符,Windows上就是Socket或者Handle了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
 

event demultiplexer——事件多路分发机制

由操作系统提供的I/O多路复用机制,比如select和epoll。程序首先将其关心的句柄(事件源)及其事件注册到event demultiplexer上;当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
它是Reactor用来检测用户注册的fd上发生的事件的利器,通过Reactor得知了哪些fd上发什么了什么样的事件,然后以这些为依据,来多路分发事件,回调用户的事件处理函数。下面是一个简单的设计:  
class EventDemultiplexer
{
public:
 
    /// 获取有事件发生的所有句柄以及所发生的事件
    /// @param  events  获取的事件
    /// @param  timeout 超时时间
    /// @retval 0       没有发生事件的句柄(超时)
    /// @retval 大于0   发生事件的句柄个数
    /// @retval 小于0   发生错误
    virtual int WaitEvents(std::map<handle_t , event_t> * events,
                           int timeout = 0) = 0;
 
    /// 设置句柄handle关注evt事件
    /// @retval 0     设置成功
    /// @retval 小于0 设置出错
    virtual int RequestEvent(handle_t handle, event_t evt) = 0;
 
    /// 撤销句柄handle对事件evt的关注
    /// @retval 0     撤销成功
    /// @retval 小于0 撤销出错
    virtual int UnrequestEvent(handle_t handle, event_t evt) = 0;
};

Reactor——反应器

Reactor,是事件管理的接口,内部使用event demultiplexer注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。
一个典型的Reactor声明方式:
class Reactor
{
public:
 
    /// 构造函数
    Reactor();
 
    /// 析构函数
    ~Reactor();
 
    /// 向reactor中注册关注事件evt的handler(可重入)
    /// @param  handler 要注册的事件处理器
    /// @param  evt     要关注的事件
    /// @retval 0       注册成功
    /// @retval -1      注册出错
    int RegisterHandler(EventHandler * handler, event_t evt);
 
    /// 从reactor中移除handler
    /// @param  handler 要移除的事件处理器
    /// @retval 0       移除成功
    /// @retval -1      移除出错
    int RemoveHandler(EventHandler * handler);
 
    /// 处理事件,回调注册的handler中相应的事件处理函数
    /// @param  timeout 超时时间(毫秒)
    void HandleEvents(int timeout = 0);
 
private:
 
    ReactorImplementation * m_reactor_impl; ///< reactor的实现类
};
 

Event Handler——事件处理程序

事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor在相应的事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。EventHander是用户和Reactor打交道的工具,用户通过向Reactor注册自己的EventHandler,可以告知Reactor在特定事件发生的时候该帮我做些什么。下面是两种典型的Event Handler类声明方式,二者互有优缺点。
class EventHandler
{
public:
 
    /// 获取该handler所对应的句柄
    virtual handle_t GetHandle() = 0;
 
    /// 处理读事件的回调函数
    virtual void HandleRead() {}
 
    /// 处理写事件的回调函数
    virtual void HandleWrite() {}
 
    /// 处理出错事件的回调函数
    virtual void HandleError() {}
 
protected:
 
    /// 构造函数,只能子类调
    EventHandler() {}
 
    /// 析构函数,只能子类调
    virtual ~EventHandler() {}
};

 

ConcreteEventHandler:
ConcreteEventHandler是EventHandler的子类,EventHandler是Reactor所用来规定接口的基类,用户自己的事件处理器都必须从EventHandler继承

Reactor事件处理流程

前面说过Reactor将事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么样子呢?可以参见下面的序列图:

reactor sequences

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多