|
Reactor模式翻譯成中文通常學叫做“反應堆”模式,強調(diào)的是回調(diào)機制與事件。
Reactor的事件處理機制
首先來回想一下普通函數(shù)調(diào)用的機制:程序調(diào)用某函數(shù),函數(shù)執(zhí)行,程序等待,函數(shù)將結(jié)果和控制權(quán)返回給程序,程序繼續(xù)處理。Reactor釋義“反應堆”,是一種事件驅(qū)動機制。和普通函數(shù)調(diào)用的不同之處在于:應用程序不是主動的調(diào)用某個API完成處理,而是恰恰相反,Reactor逆置了事件處理流程,應用程序需要提供相應的接口并注冊到Reactor上,如果相應的時間發(fā)生,Reactor將主動調(diào)用應用程序注冊的接口,這些接口又稱為“回調(diào)函數(shù)”。
Reactor模式的優(yōu)點
Reactor模式是編寫高性能網(wǎng)絡服務器的必備技術(shù)之一,它具有如下的優(yōu)點:
- 響應快,不必為單個同步時間所阻塞,雖然Reactor本身依然是同步的;
- 編程相對簡單,可以最大程度的避免復雜的多線程及同步問題,并且避免了多線程/進程的切換開銷;
- 可擴展性,可以方便的通過增加Reactor實例個數(shù)來充分利用CPU資源;
- 可復用性,reactor框架本身與具體事件處理邏輯無關,具有很高的復用性;
Reactor模式框架
使用Reactor模型,必備的幾個組件:事件源、Reactor框架、多路復用機制和事件處理程序,先來看看Reactor模型的整體框架,接下來再對每個組件做逐一說明。

-
事件源
-
- Linux上是文件描述符,Windows上就是Socket或者Handle了,這里統(tǒng)一稱為“句柄集”;程序在指定的句柄上注冊關心的事件,比如I/O事件。
-
event demultiplexer——事件多路分發(fā)機制
- 由操作系統(tǒng)提供的I/O多路復用機制,比如select和epoll。程序首先將其關心的句柄(事件源)及其事件注冊到event demultiplexer上;當有事件到達時,event demultiplexer會發(fā)出通知“在已經(jīng)注冊的句柄集中,一個或多個句柄的事件已經(jīng)就緒”;程序收到通知后,就可以在非阻塞的情況下對事件進行處理了。
- 它是Reactor用來檢測用戶注冊的fd上發(fā)生的事件的利器,通過Reactor得知了哪些fd上發(fā)什么了什么樣的事件,然后以這些為依據(jù),來多路分發(fā)事件,回調(diào)用戶的事件處理函數(shù)。下面是一個簡單的設計:
class EventDemultiplexer
{
public:
/// 獲取有事件發(fā)生的所有句柄以及所發(fā)生的事件
/// @param events 獲取的事件
/// @param timeout 超時時間
/// @retval 0 沒有發(fā)生事件的句柄(超時)
/// @retval 大于0 發(fā)生事件的句柄個數(shù)
/// @retval 小于0 發(fā)生錯誤
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,是事件管理的接口,內(nèi)部使用event demultiplexer注冊、注銷事件;并運行事件循環(huán),當有事件進入“就緒”狀態(tài)時,調(diào)用注冊事件的回調(diào)函數(shù)處理事件。
- 一個典型的Reactor聲明方式:
-
class Reactor
{
public:
/// 構(gòu)造函數(shù)
Reactor();
/// 析構(gòu)函數(shù)
~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);
/// 處理事件,回調(diào)注冊的handler中相應的事件處理函數(shù)
/// @param timeout 超時時間(毫秒)
void HandleEvents(int timeout = 0);
private:
ReactorImplementation * m_reactor_impl; ///< reactor的實現(xiàn)類
};
-
Event Handler——事件處理程序
- 事件處理程序提供了一組接口,每個接口對應了一種類型的事件,供Reactor在相應的事件發(fā)生時調(diào)用,執(zhí)行相應的事件處理。通常它會綁定一個有效的句柄。EventHander是用戶和Reactor打交道的工具,用戶通過向Reactor注冊自己的EventHandler,可以告知Reactor在特定事件發(fā)生的時候該幫我做些什么。下面是兩種典型的Event Handler類聲明方式,二者互有優(yōu)缺點。
class EventHandler
{
public:
/// 獲取該handler所對應的句柄
virtual handle_t GetHandle() = 0;
/// 處理讀事件的回調(diào)函數(shù)
virtual void HandleRead() {}
/// 處理寫事件的回調(diào)函數(shù)
virtual void HandleWrite() {}
/// 處理出錯事件的回調(diào)函數(shù)
virtual void HandleError() {}
protected:
/// 構(gòu)造函數(shù),只能子類調(diào)
EventHandler() {}
/// 析構(gòu)函數(shù),只能子類調(diào)
virtual ~EventHandler() {}
};
-
-
ConcreteEventHandler: ConcreteEventHandler是EventHandler的子類,EventHandler是Reactor所用來規(guī)定接口的基類,用戶自己的事件處理器都必須從EventHandler繼承。
-
Reactor事件處理流程
前面說過Reactor將事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么樣子呢?可以參見下面的序列圖:

|