慎用Reactor Notify机制

8 慎用Reactor Notify机制

Reactor的模式,有一种辅助的通知机制,Notify机制,简单说就是通过通知发起者调用notify函数,notify的消息被保存在一个管道中,handle_event的处理中会检查这个管道中是否有通知数据,如果有就根据通知的消息,会根据默认的通知消息的类型去调用hanle_input等函数。

从设计的角度将,这个机制无疑是非常优美的,对于Reactor,它在IO驱动以外,提供了一种新的驱动方式。但是从实现角度来讲,这个机制要慎用。原因有两个。

8.1 ACE Reactor的默认Notify方式采用的是ACE_Pipe

ACE Reactor的默认Notify方式采用的是ACE_Pipe,所以ACE_PipeWindowsLinux平台上的问题,Notify机制把ACE_Pipe的缺陷一个不少的继承了,而且问题更加多。

/**

* Contains the ACE_HANDLE the ACE_Dev_Poll_Reactor is listening

* on,as well as the ACE_HANDLE that threads wanting the attention

* of the ACE_Dev_Poll_Reactor will write to.

*/

ACE_Pipe notification_pipe_;

原来在调试ACE代码的时候,我发现只要一使用Reactor,即使只使用定时器(除非明确不使用Notify),防火墙都会报警有监听端口。我曾经对此大惑不解,直到读了ACE的这部分原代码。这样做的坏处有很多。第一个是由于采用的阻塞IO。速度会慢很多,第二个由于是单线程的处理,如果在压力极大的情况下,可能出现死锁的问题。比如在有大规模的Notify的情况下,发送缓冲区很可能会被塞满(由于是单线程,这时不会有接受者),同时由于为了简化,ACE_Pipe采用的IO是阻塞的,所以会导致整个程序死锁。第三就是这样的情况下ACE_Pipe会打开一个临时的端口,而且会绑定所有的IP 0.0.0 .0),如果对于一个安全要求严格的的场景,这个将是一个不可饶恕的错误。【注】

【注】在一个安全要求严格的环境下,这个临时端口轻则可以让你的服务器轻易陷于崩溃,重则可以让你整个网络被黑客攻陷。

不过还好的是ACE的开发者估计自己也意识倒了这个麻烦。所以提供了另外一种消息队列的方式。你可以通过定义ACE_HAS_REACTOR_NOTIFICATION_QUEUE的宏编译ACE,这样ACE将不使用ACE_Pipe作为Notify消息的管道,而使用一个自己的内存队列保存Notify消息,这个队列是动态扩展的。而且由于是内存操作,性能方面没有太大问题。

大体位置在重复编译的卫哨后面,#include /**/ "ace/pre.h"前面。保证这个宏起到作用。

#ifndef ACE_CONFIG_LINUX_H

#define ACE_CONFIG_LINUX_H

//使用内存队列作为Notify Queue

#define ACE_HAS_REACTOR_NOTIFICATION_QUEUE

#include /**/ "ace/pre.h"

这个问题到 5.6.1 还是存在的,估计由于历史的原因,在很长一段时间也不会得到解决。

8.2 考虑不周的Reactor Notify机制

同上,这也应该是一个BUGReactor Notify的代码有考虑不周的地方。Notify机制的本质是提供了一条消息队列让大家有方法调用Event_handler,但是存在一种可能,在你的通知消息在消息队列的时候,Event_hanlder由于后面的处理可能已经handle_close了。但是ACEdispatch_notify却没有考虑倒这一点(或者说考虑倒这一点也不好解决)。

ACE_Select_Reactor_Notify::dispatch_notify函数的代码。

int

ACE_Select_Reactor_Notify::dispatch_notify (ACE_Notification_Buffer &buffer)

{

…………

ACE_Event_Handler *event_handler =

buffer.eh_;

bool const requires_reference_counting =

event_handler->reference_counting_policy ().value () ==

ACE_Event_Handler::Reference_Counting_Policy::ENABLED;

//如果此时这个ACE_Event_Handler已经被handle_close了,你如何是好。。。。

switch (buffer.mask_)

{

case ACE_Event_Handler::READ_MASK:

case ACE_Event_Handler::ACCEPT_MASK:

result = event_handler->handle_input (ACE_INVALID_HANDLE);

这个bug 5.6.1 还没有解决。我觉得这个问题是可以解决的(暂时还没有提BUG),但是得到解决的方式却仍然是低效的方案(还记得取消定时器的那个缺陷吗)。

如果你仔细看过上面的几节,你也许会发出惊叹,啊,又是Reactor Notify?对,又是它。看起来我好像一直在和ACENotify机制在做对,但它的确让我吃了无数的苦头。这部分的设计的确有一点画蛇添足的感觉,而且由于跨平台性等原因,这个小编的实现一直不如意。其实自己使用ACE的实现(比如Message_Queue)一套这样的机制应该是易如反掌的事情。不苛求了。

如果你用不到Notify机制,最好在ACE_Reactor初始化的时候彻底关闭Notify机制。很多Reactor的初始化函数都提供了关闭notify pipe的方式。比如ACE_Select_Reactor_Topen函数的disable_notify_pipe参数。当其为1的时候表示关闭notify 管道。

//disable_notify_pipe参数为1时表示关闭NOTIFY PIPE,不使用他

template <class ACE_SELECT_REACTOR_TOKEN> int

ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::open

(size_t size,

int restart,

ACE_Sig_Handler *sh,

ACE_Timer_Queue *tq,

int disable_notify_pipe,/* 等于==1表示关闭notify机制 */

ACE_Reactor_Notify *notify)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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