ACE_Reactor是如何做到事件分发的

1. ACE_Reactor的创建
ctor: ACE_Reactor (ACE_Reactor_Impl *implementation = 0,int delete_implementation = 0);
你可以自己创建一个ACE_Reactor
但是大多数时候,我们都是通过调用ACE_Reactor::instance()这个静态方法来返回唯一的实例。

ACE_Reactor *
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_)
}
}
return ACE_Reactor::reactor_;
}
注意这点使用了双检测的机制(代码1和2),为了提高效率,不用每次都加锁。

2. Impl手法的运用
ACE_Reactor有个成员变量 ACE_Reactor_Impl *implementation_;
这个implementation_才是真正做事情的东西,典型的Impl手法。
为什么要多一个这个间隔层呢,主要是为了实现跨平台。
因为不同的平台的Reactor差异很大。
在Windows平台,实现这个是ACE_WFMO_Reactor
class ACE_ExportACE_WFMO_Reactor: public ACE_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
2 ACE_WFMO_Reactor::register_handler_i(ACE_HANDLEevent_handle,
3 ACE_HANDLEio_handle,
4 ACE_Event_Handler * event_handler,
5 ACE_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)
13 io_handle = event_handler -> get_handle();
14
15 if ( this -> handler_rep_.invalid_handle(io_handle))
16 {
17 errno = ERROR_INVALID_HANDLE;
18 return - 1 ;
19 }
20
21 long new_network_events = 0 ;
22 int delete_event = 0 ;
23 auto_ptr < ACE_Auto_Event > event ;
24
25 // Lookuptherepositorytoseeifthe<event_handler>isalready
26 // there.
27 ACE_Reactor_Maskold_masks;
28 int found = this -> handler_rep_.modify_network_events_i(io_handle,
29 new_masks,
30 old_masks,
31 new_network_events,
32 event_handle,
33 delete_event,
34 ACE_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( new ACE_Auto_Event);
43 event = tmp;
44 event_handle = event -> handle();
45 delete_event = 1 ;
46 }
47
48 int result = ::WSAEventSelect((SOCKET)io_handle,
49 event_handle,
50 new_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与之对应。 WaitForMultipleObjectsEx会将发生事件的socket handle的index返回。这样ACE_Reactor就可以利用这个slot来查到io_handle和event_handler( 注意:event_handle和event_handler是不同的)

1 DWORD
2 ACE_WFMO_Reactor::wait_for_multiple_events( int timeout,
3 int alertable)
4 {
5 // Waitforanyofhandles_tobeactive,oruntiltimeoutexpires.
6 // If<alertable>isenabledallowasynchronouscompletionof
7 // ReadFileandWriteFileoperations.
8
9 return ::WaitForMultipleObjectsEx( this -> handler_rep_.max_handlep1(),
10 this -> handler_rep_.handles(),
11 FALSE,
12 timeout,
13 alertable);
14 }

5.分发事件
根据WaitForMultiObjectEx返回的slot就可以查询到event_handler来调用用户的处理函数了

1 int
2 ACE_WFMO_Reactor::complex_dispatch_handler(DWORDslot,
3 ACE_HANDLEevent_handle)
4 {
5 // ThisdispatchisusedforI/Oentires.
6
7 ACE_WFMO_Reactor_Handler_Repository::Current_Info & current_info =
8 this -> handler_rep_.current_info()[slot];
9
10 WSANETWORKEVENTSevents;
11 ACE_Reactor_Maskproblems = ACE_Event_Handler::NULL_MASK;
12 if (::WSAEnumNetworkEvents((SOCKET)current_info.io_handle_,
13 event_handle,
14 & events) == SOCKET_ERROR)
15 problems = ACE_Event_Handler::ALL_EVENTS_MASK;
16 else
17 {
18 // Prepareforupcalls.Clearthebitsfrom<events>representing
19 // eventsthehandlerisnotinterestedin.Ifthereareanyleft,
20 // dotheupcall(s).upcallwillreplaceevents.lNetworkEvents
21 // withbitsrepresentinganyfunctionsthatrequestedarepeat
22 // callbackbeforecheckinghandlesagain.Inthiscase,continue
23 // tocallbackunlessthehandlerisunregisteredasaresultof
24 // oneoftheupcalls.Thewaythisiswritten,theupcallswill
25 // keepbeingdoneevenifoneormoreupcallsreportedproblems.
26 // Inpracticethismayturnoutnotsogood,butlet'ssee.Ifany
27 // problems,pleasenotifySteveHuston<shuston@riverace.com>
28 // beforeorafteryouchangethiscode.
29 events.lNetworkEvents &= current_info.network_events_;
30 while (events.lNetworkEvents != 0 )
31 {
32 ACE_Event_Handler * event_handler =
33 current_info.event_handler_;
34
35 int reference_counting_required =
36 event_handler -> reference_counting_policy().value() ==
37 ACE_Event_Handler::Reference_Counting_Policy::ENABLED;
38
39 // Calladd_reference()ifneeded.
40 if (reference_counting_required)
41 {
42 event_handler -> add_reference();
43 }
44
45 // Upcall
46 problems |= this -> upcall(current_info.event_handler_,
47 current_info.io_handle_,
48 events);
49
50 // Callremove_reference()ifneeded.
51 if (reference_counting_required)
52 {
53 event_handler -> remove_reference();
54 }
55
56 if ( this -> handler_rep_.scheduled_for_deletion(slot))
57 break ;
58 }
59 }
60
61 if (problems != ACE_Event_Handler::NULL_MASK
62 && ! this -> handler_rep_.scheduled_for_deletion(slot))
63 this -> handler_rep_.unbind(event_handle,problems);
64
65 return 0 ;
66 }
这里值得注意的是ACE通过调用WSAEnumNetworkEvents来重置event_handle。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom