加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

慎用Reactor Notify机制

发布时间:2020-12-15 05:28:16 所属栏目:百科 来源:网络整理
导读:8 慎用 Reactor Notify 机制 在 Reactor 的模式,有一种辅助的通知机制 ,Notify 机制,简单说就是通过通知发起者调用 notify 函数, notify 的消息被保存在一个管道中, handle_event 的处理中会检查这个管道中是否有通知数据,如果有就根据通知的消息,会根

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)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读