1.ACE反應(yīng)器框架簡(jiǎn)介
反應(yīng)器(Reactor):用于事件多路分離和分派的體系結(jié)構(gòu)模式
通常的,對(duì)一個(gè)文件描述符指定的文件或設(shè)備, 有兩種工作方式:?阻塞與非阻塞。所謂阻塞方式的意思是指, 當(dāng)試圖對(duì)該文件描述符進(jìn)行讀寫(xiě)時(shí),如果當(dāng)時(shí)沒(méi)有東西可讀,或者暫時(shí)不可寫(xiě), 程序就進(jìn)入等待狀態(tài), 直到有東西可讀或者可寫(xiě)為止。而對(duì)于非阻塞狀態(tài),如果沒(méi)有東西可讀, 或者不可寫(xiě), 讀寫(xiě)函數(shù)馬上返回,而不會(huì)等待。
在前面的章節(jié)中提到的Tcp通信的例子中,就是采用的阻塞式的工作方式:當(dāng)接收tcp數(shù)據(jù)時(shí),如果遠(yuǎn)端沒(méi)有數(shù)據(jù)可以讀,則會(huì)一直阻塞到讀到需要的數(shù)據(jù)為止。這種方式的傳輸和傳統(tǒng)的被動(dòng)方法的調(diào)用類似,非常直觀,并且簡(jiǎn)單有效,但是同樣也存在一個(gè)效率問(wèn)題,如果你是開(kāi)發(fā)一個(gè)面對(duì)著數(shù)千個(gè)連接的服務(wù)器程序,對(duì)每一個(gè)客戶端都采用阻塞的方式通信,如果存在某個(gè)非常耗時(shí)的讀寫(xiě)操作時(shí),其它的客戶端通信將無(wú)法響應(yīng),效率非常低下。
一種常用做法是:每建立一個(gè)Socket連接時(shí),同時(shí)創(chuàng)建一個(gè)新線程對(duì)該Socket進(jìn)行單獨(dú)通信(采用阻塞的方式通信)。這種方式具有很高的響應(yīng)速度,并且控制起來(lái)也很簡(jiǎn)單,在連接數(shù)較少的時(shí)候非常有效,但是如果對(duì)每一個(gè)連接都產(chǎn)生一個(gè)線程的無(wú)疑是對(duì)系統(tǒng)資源的一種浪費(fèi),如果連接數(shù)較多將會(huì)出現(xiàn)資源不足的情況。
另一種較高效的做法是:服務(wù)器端保存一個(gè)Socket連接列表,然后對(duì)這個(gè)列表進(jìn)行輪詢,如果發(fā)現(xiàn)某個(gè)Socket端口上有數(shù)據(jù)可讀時(shí)(讀就緒),則調(diào)用該socket連接的相應(yīng)讀操作;如果發(fā)現(xiàn)某個(gè)Socket端口上有數(shù)據(jù)可寫(xiě)時(shí)(寫(xiě)就緒),則調(diào)用該socket連接的相應(yīng)寫(xiě)操作;如果某個(gè)端口的Socket連接已經(jīng)中斷,則調(diào)用相應(yīng)的析構(gòu)方法關(guān)閉該端口。這樣能充分利用服務(wù)器資源,效率得到了很大提高。
在Socket編程中就可以通過(guò)select等相關(guān)API實(shí)現(xiàn)這一方式。但直接用這些API控制起來(lái)比較麻煩,并且也難以控制和移植,在ACE中可以通過(guò)Reactor模式簡(jiǎn)化這一開(kāi)發(fā)過(guò)程。
反應(yīng)器本質(zhì)上提供一組更高級(jí)的編程抽象,簡(jiǎn)化了事件驅(qū)動(dòng)的分布式應(yīng)用的設(shè)計(jì)和實(shí)現(xiàn)。除此而外,反應(yīng)器還將若干不同種類的事件的多路分離集成到易于使用的API中。特別地,反應(yīng)器對(duì)基于定時(shí)器的事件、信號(hào)事件、基于I/O端口監(jiān)控的事件和用戶定義的通知進(jìn)行統(tǒng)一地處理。
ACE中的反應(yīng)器與若干內(nèi)部和外部組件協(xié)同工作。其基本概念是反應(yīng)器框架檢測(cè)事件的發(fā)生(通過(guò)在OS事件多路分離接口上進(jìn)行偵聽(tīng)),并發(fā)出對(duì)預(yù)登記事件處理器(eventhandler)對(duì)象中的方法的"回調(diào)"(callback)。該方法由應(yīng)用開(kāi)發(fā)者實(shí)現(xiàn),其中含有應(yīng)用處理此事件的特定代碼。
使用ACE的反應(yīng)器,只需如下幾步:
創(chuàng)建事件處理器,以處理他所感興趣的某事件。 在反應(yīng)器上登記,通知說(shuō)他有興趣處理某事件,同時(shí)傳遞他想要用以處理此事件的事件處理器的指針給反應(yīng)器。 隨后反應(yīng)器框架將自動(dòng)地:
在內(nèi)部維護(hù)一些表,將不同的事件類型與事件處理器對(duì)象關(guān)聯(lián)起來(lái)。 在用戶已登記的某個(gè)事件發(fā)生時(shí),反應(yīng)器發(fā)出對(duì)處理器中相應(yīng)方法的回調(diào)。 反應(yīng)器模式在ACE中被實(shí)現(xiàn)為ACE_Reactor類,它提供反應(yīng)器框架的功能接口。
如上面所提到的,反應(yīng)器將事件處理器對(duì)象作為服務(wù)提供者使用。反應(yīng)器內(nèi)部記錄某個(gè)事件處理器的特定事件的相關(guān)回調(diào)方法。當(dāng)這些事件發(fā)生時(shí),反應(yīng)器會(huì)創(chuàng)建這種事件和相應(yīng)的事件處理器的關(guān)聯(lián)。
事件處理器
事件處理器就是需要通過(guò)輪詢發(fā)生事件改變的對(duì)象列表中的對(duì)象,如在上面的例子中就是連接的客戶端,每個(gè)客戶端都可以看成一個(gè)事件處理器。 回調(diào)事件
就是反應(yīng)器支持的事件,如Socket讀就緒,寫(xiě)就緒。拿上面的例子來(lái)說(shuō),如果某個(gè)客戶端(事件處理器)在反應(yīng)器中注冊(cè)了讀就緒事件,當(dāng)客戶端給服務(wù)器發(fā)送一條消息的時(shí)候,就會(huì)觸發(fā)這個(gè)客戶端的數(shù)據(jù)可讀的回調(diào)函數(shù)。 在反應(yīng)器框架中,所有應(yīng)用特有的事件處理器都必須由ACE_Event_Handler的抽象接口類派生。可以通過(guò)重載相應(yīng)的"handle_"方法實(shí)現(xiàn)相關(guān)的回調(diào)方法。
使用ACE_Reactor基本上有三個(gè)步驟:
創(chuàng)建ACE_Event_Handler的子類,并在其中實(shí)現(xiàn)適當(dāng)?shù)?#34;handle_"方法,以處理你想要此事件處理器為之服務(wù)的事件類型。 通過(guò)調(diào)用反應(yīng)器對(duì)象的register_handler(),將你的事件處理器登記到反應(yīng)器。 在事件發(fā)生時(shí),反應(yīng)器將自動(dòng)回調(diào)相應(yīng)的事件處理器對(duì)象的適當(dāng)?shù)膆andle_"方法。 下面我就以一個(gè)Socket客戶端的例子為例簡(jiǎn)單的說(shuō)明反應(yīng)器的基本用法。
?
Cpp代碼??
#include?<ace/OS.h>?? #include?<ace/Reactor.h>?? #include?<ace/SOCK_Connector.h>??? ?? #include?<string>?? #include?<iostream>?? using?namespace?std;?? ?? class?MyClient:public?ACE_Event_Handler??? {?? public:?? ????bool?open()?? ????{?? ????????ACE_SOCK_Connector?connector;?? ????????ACE_INET_Addr?addr(3000,"127.0.0.1");?? ????????ACE_Time_Value?timeout(5,0);?? ????????if(connector.connect(peer,addr,&timeout)?!=?0)?? ????????{?? ????????????cout<<endl<<"connecetd?fail";?? ????????????return?false;?? ????????}?? ????????ACE_Reactor::instance()->register_handler(this,ACE_Event_Handler::READ_MASK);?? ????????cout<<endl<<"connecetd?";?? ????????return?true;?? ????}?? ?? ????ACE_HANDLE?get_handle(void)?const?? ????{?? ????????return?peer.get_handle();?? ????}?? ?? ????int?handle_input?(ACE_HANDLE?fd)?? ????{?? ????????int?rev=0;?? ????????ACE_Time_Value?timeout(5,0);?? ????????if((rev=peer.recv(buffer,1000,&timeout))>0)?? ????????{?? ????????????buffer[rev]='\0';?? ????????????cout<<endl<<"rev:\t"<<buffer<<endl;?? ????????}?? ????????return?3;?? ????}?? ?? private:?? ????ACE_SOCK_Stream?peer;?? ????char?buffer[1024];?? };?? ?? int?main(int?argc,?char?*argv[])??? {?? ????MyClient?client;?? ????client.open();?? ?? ????while(true)?? ????{?? ????????ACE_Reactor::instance()->handle_events();??? ????}?? ?? ????return?0;??? }?? ? ?
在這個(gè)例子中,客戶端連接上服務(wù)器后,通過(guò)ACE_Reactor::instance()->register_handler(this,ACE_Event_Handler::READ_MASK)注冊(cè)了一個(gè)讀就緒的回調(diào)函數(shù),當(dāng)服務(wù)器端給客戶端發(fā)消息的時(shí)候,會(huì)自動(dòng)觸發(fā)handle_input()函數(shù),將接收到的信息打印出來(lái)。
這個(gè)例子只是為了演示反應(yīng)器的基本用法,并不完善,我將在下一節(jié)中對(duì)如何在Socket通信中使用反應(yīng)器做進(jìn)一步的介紹。
?
在Socket編程中,常見(jiàn)的事件就是"讀就緒","寫(xiě)就緒",通過(guò)對(duì)這兩個(gè)事件的捕獲分發(fā),可以實(shí)現(xiàn)Socket中的異步操作。
Socket編程中的事件處理器
在前面我們已經(jīng)介紹過(guò),在ACE反應(yīng)器框架中,任何都必須派生自ACE_Event_Handler類,并通過(guò)重載其相應(yīng)會(huì)調(diào)事件處理函數(shù)來(lái)實(shí)現(xiàn)相應(yīng)的回調(diào)處理的。在Socket編程中,我們通常需要重載的函數(shù)有
handle_input()
當(dāng)I/O句柄(比如UNIX中的文件描述符)上的輸入可用時(shí),反應(yīng)器自動(dòng)回調(diào)該方法。 handle_output()
當(dāng)I/O設(shè)備的輸出隊(duì)列有可用空間時(shí),反應(yīng)器自動(dòng)回調(diào)該方法。 handle_close()
當(dāng)事件處理器中的事件從Reactor中移除的時(shí)候調(diào)用。 此外,為了使Reactor能通過(guò)I/O句柄找到對(duì)應(yīng)的事件處理器,還必須重載其get_handle()方法以使得Reactor建立起I/O句柄和事件處理器的關(guān)聯(lián)。
使用Reactor框架。
下面我們將以一個(gè)客戶端的程序?yàn)槔?#xff0c;介紹如何在Socket編程中使用Reactor框架。
一.建立一個(gè)客戶端對(duì)象(事件處理器)。
客戶端對(duì)象就是一個(gè)事件處理器,其聲明如下:
?
Cpp代碼??
class?Client:public?ACE_Event_Handler?? {?? public:?? ????ACE_HANDLE?get_handle(void)?const;?? ????int?handle_input?(ACE_HANDLE?fd);?? ????int?handle_close?(ACE_HANDLE?handle,?? ACE_Reactor_Mask?close_mask);?? ????ACE_SOCK_Stream&?Peer();?? private:?? ????ACE_SOCK_Stream?peer;?? };?? ? ?
在Client端中我只關(guān)心"讀就緒"事件,故只重載了handle_input函數(shù)(大多數(shù)應(yīng)用下只需要重載handle_input函數(shù))。另外,在客戶端還保存了一個(gè)ACE_SOCK_Stream的peer對(duì)象用來(lái)進(jìn)行Socket通信,同時(shí)封裝了一個(gè)Peer()函數(shù)返回它的引用。
二.重載相應(yīng)回調(diào)處理函數(shù)
?
Cpp代碼??
ACE_SOCK_Stream&?Client::Peer()?? {?? ????return?peer;?? }?? ?? ACE_HANDLE?Client::get_handle(void)?const?? {?? ????return?peer.get_handle();?? }?? ?? int?Client::handle_input?(ACE_HANDLE?fd)?? {?? ????int?rev=0;?? ????if((rev?=?peer.recv(buffer,1000))>0)?? ????{?? ????????buffer[rev]='\0';?? ????????cout<<endl<<"rev:\t"<<buffer<<endl;?? ????????return?0;?? ????}?? ????else????//Socket連接發(fā)生錯(cuò)誤,返回-1,在Reactor中注銷事件,觸發(fā)handle_close函數(shù)?? ????{?? ????????return?-1;?? ????}?? }?? ?? int?Client::handle_close?(ACE_HANDLE?handle,?? ?????????????????????????ACE_Reactor_Mask?close_mask)?? {?? ????cout<<endl<<"connecetd?closed";?? ????return?ACE_Event_Handler::handle_close(handle,close_mask);?? }?? ? ?
幾個(gè)函數(shù)的功能都非常簡(jiǎn)單,這里就不多做介紹了。
三.在Reactor中注冊(cè)事件
首先讓我們來(lái)看看相應(yīng)的main函數(shù)的代碼:
?
Cpp代碼??
int?main(int?argc,?char?*argv[])??? {?? ????Client?client;?? ????ACE_SOCK_Connector?connector;?? ????ACE_INET_Addr?addr(3000,"127.0.0.1");?? ????ACE_Time_Value?timeout(5,0);?? ????if(connector.connect(client.Peer(),addr,&timeout)?!=?0)?? ????{?? ????????cout<<endl<<"connecetd?fail";?? ????????return?0;?? ????}?? ?? ????ACE_Reactor::instance()->register_handler(&client,ACE_Event_Handler::READ_MASK);?? ?? while(true)?? {?? ACE_Reactor::instance()->handle_events();??? }?? ?? return?0;??? }?? ? ?
在這里可以看到,使用Reactor框架后,依然首先通過(guò)ACE_SOCK_Connector的connect函數(shù)來(lái)建立連接。建立連接后,可以通過(guò)ACE_Reactor::instance()->register_handler函數(shù)來(lái)實(shí)現(xiàn)Reactor的注冊(cè),實(shí)現(xiàn)I/O事件和Client對(duì)象的handle_input方法相關(guān)聯(lián),它的第一個(gè)參數(shù)是事件處理器的地址,第二個(gè)參數(shù)是事件類型,由于這里只關(guān)心讀就緒事件,故注冊(cè)的事件類型是ACE_Event_Handler::READ_MASK。
四.啟動(dòng)Reactor事件循環(huán)
通過(guò)如上設(shè)置后,我們就可以通過(guò)ACE_Reactor::instance()->handle_events()啟動(dòng)Reactor循環(huán)了,這樣,每當(dāng)服務(wù)器端有數(shù)據(jù)發(fā)送給客戶端時(shí),當(dāng)客戶端的數(shù)據(jù)就緒時(shí),就回觸發(fā)Client對(duì)象的handle_input函數(shù),將接收的數(shù)據(jù)打印出來(lái)。
通常的做法是,將Reactor事件循環(huán)作為一個(gè)單獨(dú)的線程來(lái)處理,這樣就不會(huì)阻塞main函數(shù)。
五.注銷Reactor事件
Reactor事件的注銷一般有兩種方式,顯式和隱式,下面將分別給予介紹。
隱式注銷。
當(dāng)Reactor捕獲事件后,會(huì)觸發(fā)相應(yīng)的"handle_"處理函數(shù),當(dāng)"handle_"處理函數(shù)返回值大于或等于0時(shí),表示處理事件成功,當(dāng)返回值小于0時(shí),表示處理事件失敗,這時(shí)Reactor會(huì)自動(dòng)注銷該句柄所注冊(cè)的所有事件,并觸發(fā)handle_close函數(shù),以執(zhí)行相應(yīng)的資源清理工作。
在本例中,當(dāng)handle_input函數(shù)里的recv函數(shù)接收到0個(gè)數(shù)時(shí),說(shuō)明socket發(fā)生錯(cuò)誤(大多為Socket連接中斷),此時(shí)返回-1,則系統(tǒng)自動(dòng)注銷相應(yīng)事件。 顯示注銷。
調(diào)用Reactor對(duì)象的remove_handler方法移除,它有兩個(gè)參數(shù),第一個(gè)是所注冊(cè)的事件反應(yīng)器對(duì)象,第二個(gè)是所要注銷的事件。 在這個(gè)示例程序里,連接方只有一個(gè)Socket連接,Reactor的優(yōu)勢(shì)并沒(méi)有體現(xiàn)出來(lái),但在一些網(wǎng)絡(luò)管理系統(tǒng)里,連接方需要對(duì)多個(gè)需要管理的設(shè)備(服務(wù)器端)進(jìn)行連接,在這種情況下使用Reactor模式,只需要多開(kāi)一個(gè)Reactor事件循環(huán)線程就能實(shí)現(xiàn)事件多路分發(fā)復(fù)用,并且不會(huì)阻塞,通過(guò)面向?qū)ο蟮幕卣{(diào)方式管理,使用起來(lái)非常方便。
Reactor框架的另外一個(gè)常用的地方就是服務(wù)器端,一般是一個(gè)服務(wù)器端對(duì)應(yīng)多個(gè)客戶端,這樣用Reactor模式能大幅提高并發(fā)能力,這方面的編程方法將在下一章給與介紹。
?
在服務(wù)器端使用Reactor框架
使用Reactor框架的服務(wù)器端結(jié)構(gòu)如下:
服務(wù)器端注冊(cè)兩種事件處理器,ClientAcceptor和ClientService,ClientService類負(fù)責(zé)和客戶端的通信,每一個(gè)ClientService對(duì)象對(duì)應(yīng)一個(gè)客戶端的Socket連接。ClientAcceptor專門(mén)負(fù)責(zé)被動(dòng)接受客戶端的連接,并創(chuàng)建ClientService對(duì)象。這樣,在一個(gè)N個(gè)Socket連接的服務(wù)器程序中,將存在1個(gè)ClientAcceptor對(duì)象和N個(gè)ClientService對(duì)象。
整個(gè)服務(wù)器端流程如下:
首先創(chuàng)建一個(gè)ClientAcceptor對(duì)象,該對(duì)象在Reactor上注冊(cè)ACCEPT_MASK事件,Reactor將自動(dòng)在監(jiān)聽(tīng)端口建立Socket監(jiān)聽(tīng)。 如果有對(duì)該端口的Socket連接時(shí),Reactor將自動(dòng)回調(diào)handle_input方法,ClientAcceptor重載此方法,并創(chuàng)建一個(gè)ClientService對(duì)象,用于處理和Client的通信。 ClientService對(duì)象根據(jù)服務(wù)器的具體功能實(shí)現(xiàn),其處理過(guò)程和客戶端程序類似,注冊(cè)相應(yīng)的回調(diào)事件并分發(fā)即可。 代碼如下:
?
Cpp代碼??
#include?<ace/OS.h>?? #include?<ace/Reactor.h>?? #include?<ace/SOCK_Connector.h>??? #include?<ace/SOCK_Acceptor.h>??? #include?<ace/Auto_Ptr.h>?? ?? class?ClientService?:?public?ACE_Event_Handler?? {?? public:?? ????ACE_SOCK_Stream?&peer?(void)?{?return?this->sock_;?}?? ?? ????int?open?(void)?? ????{?? ????????//注冊(cè)讀就緒回調(diào)函數(shù)?? ????????return?this->reactor?()->register_handler(this,?ACE_Event_Handler::READ_MASK);?? ????}?? ?? ????virtual?ACE_HANDLE?get_handle?(void)?const?{?return?this->sock_.get_handle?();?}?? ?? ????virtual?int?handle_input?(ACE_HANDLE?fd?)?? ????{?? ????????//一個(gè)簡(jiǎn)單的EchoServer,將客戶端的信息返回?? ????????int?rev?=?peer().recv(buf,100);?? ????????if(rev<=0)?? ????????????return?-1;?? ?? ????????peer().send(buf,rev);?? ????????return?0;?? ????}?? ?? ????//?釋放相應(yīng)資源?? virtual?int?handle_close?(ACE_HANDLE,?ACE_Reactor_Mask?mask)?? ????{?? ????????if?(mask?==?ACE_Event_Handler::WRITE_MASK)?? ????????????return?0;?? ????????mask?=?ACE_Event_Handler::ALL_EVENTS_MASK?|?? ????????????ACE_Event_Handler::DONT_CALL;?? ????????this->reactor?()->remove_handler?(this,?mask);?? ????????this->sock_.close?();?? ????????delete?this;????//socket出錯(cuò)時(shí),將自動(dòng)刪除該客戶端,釋放相應(yīng)資源?? ????????return?0;?? ????}?? ?? protected:?? ????char?buf[100];?? ????ACE_SOCK_Stream?sock_;?? };?? ?? class?ClientAcceptor?:?public?ACE_Event_Handler?? {?? public:?? ????virtual?~ClientAcceptor?(){this->handle_close?(ACE_INVALID_HANDLE,?0);}?? ?? ????int?open?(const?ACE_INET_Addr?&listen_addr)?? ????{?? ????????if?(this->acceptor_.open?(listen_addr,?1)?==?-1)?? ????????{?? ????????????ACE_OS::printf("open?port?fail");?? ????????????return?-1;?? ????????}?? ????????//注冊(cè)接受連接回調(diào)事件?? ????????return?this->reactor?()->register_handler(this,?ACE_Event_Handler::ACCEPT_MASK);?? ????}?? ?? ????virtual?ACE_HANDLE?get_handle?(void)?const?? ????{?return?this->acceptor_.get_handle?();?}?? ?? ????virtual?int?handle_input?(ACE_HANDLE?fd?)?? ????{?? ????????ClientService?*client?=?new?ClientService();?? ????????auto_ptr<ClientService>?p?(client);?? ?? ????????if?(this->acceptor_.accept?(client->peer?())?==?-1)?? ????????{?? ????????????ACE_OS::printf("accept?client?fail");?? ????????????return?-1;?? ????????}?? ????????p.release?();?? ????????client->reactor?(this->reactor?());?? ????????if?(client->open?()?==?-1)?? ????????????client->handle_close?(ACE_INVALID_HANDLE,?0);?? ????????return?0;?? ????}?? ?????? ????virtual?int?handle_close?(ACE_HANDLE?handle,?? ????????ACE_Reactor_Mask?close_mask)?? ????{?? ????????if?(this->acceptor_.get_handle?()?!=?ACE_INVALID_HANDLE)?? ????????{?? ????????????ACE_Reactor_Mask?m?=?ACE_Event_Handler::ACCEPT_MASK?|?? ????????????????ACE_Event_Handler::DONT_CALL;?? ????????????this->reactor?()->remove_handler?(this,?m);?? ????????????this->acceptor_.close?();?? ????????}?? ????????return?0;?? ????}?? ?? protected:?? ????ACE_SOCK_Acceptor?acceptor_;?? };?? ?? int?main(int?argc,?char?*argv[])??? {?? ????ACE_INET_Addr?addr(3000,"192.168.1.142");?? ????ClientAcceptor?server;?? ????server.reactor(ACE_Reactor::instance());?? ????server.open(addr);?? ?? ????while(true)?? ????{?? ????????ACE_Reactor::instance()->handle_events();??? ????}?? ?? ????return?0;??? }?? ? ?
代碼功能比較簡(jiǎn)單,需要注意以下幾點(diǎn):
這里注冊(cè)事件的方式和前面的文章中方式不一樣,是通過(guò)ACE_Event_Handler類的reactor()方法設(shè)置和獲取reactor的指針,比較直觀和方便。前面的文章是通過(guò)ACE_Reactor::instance()來(lái)獲取的一個(gè)單體reactor的指針。 當(dāng)客戶端Socket連接關(guān)閉時(shí),需要釋放相應(yīng)資源,需要注意一下ClientService對(duì)象的handle_close方法中釋放資源的相應(yīng)代碼。
定時(shí)器的實(shí)現(xiàn)
通過(guò)Reactor機(jī)制,還可以很容易的實(shí)現(xiàn)定時(shí)器的功能,使用方式如下。
編寫(xiě)一個(gè)事件反應(yīng)器,重載handle_timeout()方法,該方法是定時(shí)器的觸發(fā)時(shí)間到時(shí),會(huì)自動(dòng)觸發(fā)該方法。 通過(guò)Reactor的schedule_timer()方法注冊(cè)定時(shí)器。 啟動(dòng)reacotr的handle_events()事件分發(fā)循環(huán)。 當(dāng)不想使用定時(shí)器時(shí),可以通過(guò)Reactor的cancel_timer()方法注銷定時(shí)器。 下面的代碼簡(jiǎn)單的實(shí)現(xiàn)了一個(gè)定時(shí)器,并具有基本的開(kāi)啟,關(guān)閉功能。
?
Cpp代碼??
#include?<ace/OS.h>?? #include?<ace/Reactor.h>?? ?? class?MyTimerHandler?:?public?ACE_Event_Handler?? {?? private:?? ????int?inteval;????//執(zhí)行時(shí)間間隔?? ????int?delay;????????//延遲執(zhí)行時(shí)間?? ????int?timerid;?? ?? public:?? ????MyTimerHandler(int?delay,int?inteval)?? ????{?? ????????this->delay=delay;?? ????????this->inteval=inteval;?? ????}?? ?? ????int?open()????//注冊(cè)定時(shí)器?? ????{?? ????????ACE_Time_Value?delaytime(inteval);?? ????????ACE_Time_Value?intevaltime(inteval);?? ????????timerid?=?reactor()->schedule_timer(this,?? ????????????0,????//傳遞handle_timeout給的參數(shù)?? ????????????delaytime,?? ????????????intevaltime);?? ????????return?timerid;?? ????}?? ?? ????int?close()????//取消定時(shí)器?? ????{?? ????????return?reactor()->cancel_timer(timerid);?? ????}?? ?? ????//定時(shí)器回調(diào)函數(shù)?? ????int?handle_timeout?(const?ACE_Time_Value?¤t_time,?? ????????const?void?*?=?0)?? ????{?? ????????time_t?epoch?=?((timespec_t)current_time).tv_sec;?? ????????ACE_DEBUG?((LM_INFO,?? ????????????ACE_TEXT?("handle_timeout:?%s\n"),?? ????????????ACE_OS::ctime?(&epoch)));?? ????????return?0;?? ????}?? };?? ?? int?main(int?argc,?char?*argv[])??? {?? ????MyTimerHandler?*?timer?=?new?MyTimerHandler?(3,5);?? ????timer->reactor(ACE_Reactor::instance());?? ????timer->open();?? ?? ????for(int?i=0;i<2;i++)????//觸發(fā)次handle_timeout事件?? ????{?? ????????ACE_OS::printf("\n%d\n",i);?? ????????ACE_Reactor::instance()->handle_events();?? ????}?? ?? ????timer->close();?? ????ACE_OS::printf("cancel?timer");?? ????while(true)?? ????????ACE_Reactor::instance()->handle_events();?? ????return?0;??? }?? ? ?
代碼功能比較簡(jiǎn)單,這里就不多做介紹了。
總結(jié)
以上是生活随笔為你收集整理的ACE反应器(Reactor)模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。