[ACE源码分析]ACE_Reactor是如何做到事件分发的
发布时间:2020-12-15 04:55:31 所属栏目:百科 来源:网络整理
导读:[ACE源码分析]ACE_Reactor是如何做到事件分发的 转载自:http://www.cppblog.com/sandy/archive/2006/02/23/3451.html 1. ACE_Reactor的创建 ACE_Reactor : ACE_Reactor (ACE_Reactor_Impl *implementation = 0,int delete_implementation = 0); 你可以自己
[ACE源码分析]ACE_Reactor是如何做到事件分发的
转载自:http://www.cppblog.com/sandy/archive/2006/02/23/3451.html
1. ACE_Reactor的创建
ACE_Reactor: ACE_Reactor (ACE_Reactor_Impl *implementation = 0,int delete_implementation = 0); 你可以自己创建一个ACE_Reactor 但是大多数时候,我们都是通过调用ACE_Reactor::instance()这个静态方法来返回唯一的实例。
ACE_Reactor*
注意这点使用了双检测的机制(代码1和2),为了提高效率,不用每次都加锁。
ACE_Reactor::instance( void) { ACE_TRACE("ACE_Reactor::instance"); if(ACE_Reactor::reactor_==0) //1 { // PerformDouble-CheckedLockingOptimization. ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex,ace_mon, *ACE_Static_Object_Lock::instance(),0)); if(ACE_Reactor::reactor_==0) //2 { ACE_NEW_RETURN(ACE_Reactor::reactor_, ACE_Reactor, 0); ACE_Reactor::delete_reactor_=1; ACE_REGISTER_FRAMEWORK_COMPONENT(ACE_Reactor,ACE_Reactor::reactor_) } } returnACE_Reactor::reactor_; } 2. Impl手法的运用 ACE_Reactor有个成员变量 ACE_Reactor_Impl *implementation_; 这个implementation_才是真正做事情的东西,典型的Impl手法。 为什么要多一个这个间隔层呢,主要是为了实现跨平台。 因为不同的平台的Reactor差异很大。 在Windows平台,实现这个是ACE_WFMO_Reactor classACE_ExportACE_WFMO_Reactor: publicACE_Reactor_Impl 3. Event_Handle的管理 ACE_WFMO_Reactor把要管理的Handle都放在 ACE_WFMO_Reactor_Handler_Repository handler_rep_; 这里要注意的是io_handle和event_handle的区别 io_handle是真正的handle,比如socket_handle,thread_handle 而event_handle是绑定在io_handle上面的事件handle 有代码为证: 1 int 2ACE_WFMO_Reactor::register_handler_i(ACE_HANDLEevent_handle, 3ACE_HANDLEio_handle,128)">4ACE_Event_Handler*event_handler,128)">5ACE_Reactor_Masknew_masks) 6{ 7 IfthisisaWinsock1system,theunderlyingeventassignmentwill 8 notwork,sodon'ttry.Winsock1mustuseACE_Select_Reactorfor 9 reactingtosocketactivity. 10 11 Makesurethatthe<handle>isvalid 12 if(io_handle==ACE_INVALID_HANDLE) 13io_handle=event_handler->get_handle(); 14 15 if( this->handler_rep_.invalid_handle(io_handle)) 16{ 17errno=ERROR_INVALID_HANDLE; 18 return-1; 19} 20 21 longnew_network_events=0; 22 intdelete_event=0; 23auto_ptr<ACE_Auto_Event> event; 24 25 Lookuptherepositorytoseeifthe<event_handler>isalready 26 there. 27 ACE_Reactor_Maskold_masks; 28 intfound= this->handler_rep_.modify_network_events_i(io_handle,128)">29new_masks,128)">30old_masks,128)">31new_network_events,128)">32event_handle,128)">33delete_event,128)">34ACE_Reactor::ADD_MASK); 35 36 Checktoseeiftheuserpassedusavalidevent;Ifnotthenwe 37 needtocreateone 38 if(event_handle==ACE_INVALID_HANDLE) 39{ 40 Note:don'tchangethissincesomeC++compilershave 41 <auto_ptr>sthatdon'tworkproperly 42 auto_ptr<ACE_Auto_Event>tmp( newACE_Auto_Event); 43 event=tmp; 44event_handle= event->handle(); 45delete_event=1; 46} 47 48 intresult=::WSAEventSelect((SOCKET)io_handle,128)">49event_handle,128)">50new_network_events); 可以看到在42行create event,在44复制到event_handle,最后通过 WSAEventSelect 将这个io_handle和event_handle绑定在一起了 这个register_handle调用一般都在Event_Handler的open函数中,实现了注册到Reactor中去。 4. 等待事件 如何检测到要发生的socket的事件呢?比如有新的client连接,收发。ACE并不直接调用select函数来取得。 ACE调用 WaitForMultipleObjectsEx 来等待事件的发生。ACE这样做的好处是不但可以捕捉socket事件,也可以捕捉到其他事件。前面说过了每一个对应的socket都有一个event_handle与之对应。 会将发生事件的socket handle的index返回。这样ACE_Reactor就可以利用这个slot来查到io_handle和event_handler( 注意:event_handle和event_handler是不同的) 1DWORD 2ACE_WFMO_Reactor::wait_for_multiple_events( inttimeout,128)">3 intalertable) 4{ 5 Waitforanyofhandles_tobeactive,oruntiltimeoutexpires. 6 If<alertable>isenabledallowasynchronouscompletionof ReadFileandWriteFileoperations. return::WaitForMultipleObjectsEx( this->handler_rep_.max_handlep1(),255)">this->handler_rep_.handles(),128)">11FALSE,128)">12timeout,128)">13alertable); 14} 5.分发事件 根据WaitForMultiObjectEx返回的slot就可以查询到event_handler来调用用户的处理函数了 2ACE_WFMO_Reactor::complex_dispatch_handler(DWORDslot,128)">3ACE_HANDLEevent_handle) ThisdispatchisusedforI/Oentires. 7ACE_WFMO_Reactor_Handler_Repository::Current_Info¤t_info= this->handler_rep_.current_info()[slot]; 9 10WSANETWORKEVENTSevents; 11ACE_Reactor_Maskproblems=ACE_Event_Handler::NULL_MASK; if(::WSAEnumNetworkEvents((SOCKET)current_info.io_handle_,128)">13event_handle,128)">14&events)==SOCKET_ERROR) 15problems=ACE_Event_Handler::ALL_EVENTS_MASK; 16 else 17{ Prepareforupcalls.Clearthebitsfrom<events>representing 19 eventsthehandlerisnotinterestedin.Ifthereareanyleft, 20 dotheupcall(s).upcallwillreplaceevents.lNetworkEvents withbitsrepresentinganyfunctionsthatrequestedarepeat callbackbeforecheckinghandlesagain.Inthiscase,continue 23 tocallbackunlessthehandlerisunregisteredasaresultof 24 oneoftheupcalls.Thewaythisiswritten,theupcallswill keepbeingdoneevenifoneormoreupcallsreportedproblems. Inpracticethismayturnoutnotsogood,butlet'ssee.Ifany problems,pleasenotifySteveHuston<shuston@riverace.com> beforeorafteryouchangethiscode. 29 events.lNetworkEvents&=current_info.network_events_; 30 while(events.lNetworkEvents!=0) 31{ 32ACE_Event_Handler*event_handler= 33current_info.event_handler_; 34 35 intreference_counting_required= 36event_handler->reference_counting_policy().value()== 37ACE_Event_Handler::Reference_Counting_Policy::ENABLED; 38 39 Calladd_reference()ifneeded. if(reference_counting_required) 41{ 42event_handler->add_reference(); 43} 44 45 Upcall 46 problems|= this->upcall(current_info.event_handler_,128)">47current_info.io_handle_,128)">48events); 49 50 Callremove_reference()ifneeded. 51 52{ 53event_handler->remove_reference(); 54} 55 56 this->handler_rep_.scheduled_for_deletion(slot)) 57 break; 58} 59} 60 61 if(problems!=ACE_Event_Handler::NULL_MASK 62&&! 63 this->handler_rep_.unbind(event_handle,problems); 64 65 return0; 66} 这里值得注意的是ACE通过调用WSAEnumNetworkEvents来重置event_handle。 讲的比较概要,更具体的细节请自己阅读源码。 关于ACE_Reactor的用法请参见前一篇我的示例。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |