小技巧: 当ACE_Svc_Handler关闭时使用的默认行为

部署运行你感兴趣的模型镜像

小技巧: 当ACE_Svc_Handler关闭时使用的默认行为

 Stone Jiang


上一篇我们看了ACE_Svc_Handler::open()挂勾函数提供默认行为的一些技巧。因为在大多数情况下,它完成了服务创建时所需的所有事情:为输入事件注册新处理器和返回。


在ACE_Svc_Handler中关闭操作的默认行为要比在open()中初始化的代码更为复杂。这是因为关闭时的挂勾函数包含了反应式(reactive)关闭和主动式(active-object)关闭两种情

况,它们有相同的效果:删除所有在反应器注册的事件和确保删除ACE_Svc_handler的派生类的对象。

 

反应式关闭(handle_close()): 当以下形况发生时被调用:
 1) 事件回调函数(译注:handle_xxxx())返回-1时,或
 2) 调用ACE_Reactor::remove_handler(),传入的标记不含 DONT_CALL时
 反应器框架将调用handle_close()挂勾函数。 ACE_Svc_handler::handle_close()的默认行为是调用ACE_Svc_Handler::destroy()销毁事件处理器。


主动对象式关闭(close()): 当ACE_Svc_Handler 派生的对象通过activate()函数转变为主动对象,处理器的的svc()方法在它产生的线程中运行后进行回调。当svc()返回时,线程

退出,但在它要退出时,仍在将要退出线程的上下文中,ACE_Task框架调用它的close()方法。ACE_Svc_Handler::close()方法调用handle_close()完成服务处理器的清理工作。

因此,不管ACE_Svc_Handler对象是反应式还是主动式,结束时的清理工作都在相同的地方:ACE_Svc_Handler::destroy()。如果对象是动态分配且不是ACE_Stream框架中的组成部

分,destroy()将删除此对象,如果对象不是动态分配的,析构它的责任是创建时对象所在的封闭范围。如果对象是ACE_Stream的模块的组成部分,流和/或控制流的代码负责管理

对象的生命期。destroy()函数应遵守这样的规则来避免出现资源泄漏。


无论ACE_Svc_Handler对象是反应式销毁还是主动式销毁,都会引起相同的事情发生:~ACE_Svc_Handler() (处理器的析构函数)调用ACE_Svc_Handler::shutdown()函数完成服务处

理器的清理工作。shutdown()执行的这些清理操作是:

 

如果处理器与反应器是关联的:
   取消处理器关联的所有定时器。
   为处理器的流对象(如socket)删除所有已注册的事件。
如果处理器与再生器(recycler)是关系的,从再生器中清除处理器。
关闭流对象。
因此,我们看到的绝大多数情况服务处理器通过shutdown需要通过框架来清理工作,都是简单的允许缺省的挂勾函数得以被调用。如果你的应用程序需求更多的关闭/清理规则,推

荐的地方是你的处理器的handle_close()挂勾方法。仅仅是确保把ACE_Svc_Handler::destroy()函数人作为你的handle_close()的最后一个动作,与框架清理行为的余下的行为合

并。


 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>我们正在处理关于ACE框架中事件处理器注销的问题。根据引用内容,注销事件处理器有两种方式:隐式自动拆除和显式拆除。用户特别关注如何取消READ_MASK事件的处理,即注销对读事件的处理。引用[1]提到:-隐式拆除:当事件处理器类中的handle_***方法返回小于0,反应器会自动调用handle_close()方法并拆除事件处理器。-显式拆除:调用ACE_reactor::remove_handler(),并可以选择是否调用handle_close()方法。引用[2]说明了事件处理器的基本使用步骤,包括注册和回调。引用[3]给出了一个代码示例,其中在handle_input方法中通过返回-1来触发隐式拆除(注意该示例中在accept后返回-1,这样会导致当前事件处理器被拆除?但实际上该示例中是在接收新连接后注册了新的处理器,并返回-1,那么它实际上是在每次接收一个连接后就会拆除自己?这显然不是我们想要的,因为通常接受器会持续工作。所以这里可能是个错误或者特殊设计?)用户的问题:如何注销ACE_Event_Handler中的READ_MASK事件?分析:我们想要注销的是某个事件处理器上的READ_MASK事件(即不再监听读事件),但保留其他事件(如果有)或者完全拆除该事件处理器。根据ACE文档,有两种方式:1.显式调用remove_handler()来移除特定的事件类型(如READ_MASK)或者移除整个事件处理器。2.在handle_*方法中返回一个负值(比如-1)来触发整个事件处理器的拆除(包括所有事件类型)。注意:如果我们只想移除READ_MASK,而保留其他事件(比如WRITE_MASK),那么就需要使用显式拆除并指定事件类型。具体方法:显式拆除:intremove_handler(ACE_HANDLEhandle,ACE_Reactor_Maskmask);其中,mask就是要移除的事件集,比如READ_MASK。代码示例:reactor()->remove_handler(handler->get_handle(),ACE_Event_Handler::READ_MASK);这样,反应器将不再监听该句柄上的读事件,但其他事件(如果注册了)还会继续监听。如果我们想完全移除该事件处理器,可以调用:reactor()->remove_handler(handler->get_handle(),ACE_Event_Handler::ALL_EVENTS_MASK);或者reactor()->remove_handler(handler);//这个版本不需要句柄,但需要事件处理器对象另外,在remove_handler默认会调用事件处理器的handle_close方法(传入mask参数为0)。如果不想调用handle_close,可以传递标志位ACE_Event_Handler::DONT_CALL。示例代码(参考引用[3]的格式):假设我们有一个事件处理器对象,它已经注册了读事件(READ_MASK)。现在我们要取消读事件监听:reactor->remove_handler(my_handler->get_handle(),ACE_Event_Handler::READ_MASK);如果我们在事件处理器内部调用,可以直接使用反应器实例:ACE_Reactor::instance()->remove_handler(get_handle(),ACE_Event_Handler::READ_MASK);注意:在移除特定事件后,如果该事件处理器还注册了其他事件,那么它仍然会处理那些事件。如果没有任何事件了,反应器将不再调用该事件处理器。另外,隐式方法:在handle_input方法中返回-1,将会导致整个事件处理器被拆除(即移除所有事件并调用handle_close)。但这样会移除所有事件,而不仅仅是读事件。因此,根据用户需求,如果只想注销READ_MASK,那么应该使用显式方法。下面给出一个代码示例片段:```cppclassMyEventHandler:publicACE_Event_Handler{public://...其他方法//假设我们想要在某个条件下取消读事件voidcancel_read_event(){//获取反应器实例ACE_Reactor*reactor=ACE_Reactor::instance();//移除当前句柄上的读事件reactor->remove_handler(this->get_handle(),ACE_Event_Handler::READ_MASK);}//句柄获取ACE_HANDLEget_handle()constoverride{//返回你管理的句柄,比如socket句柄returnyour_handle_;}//处理读事件inthandle_input(ACE_HANDLEh)override{//处理读事件...//如果我们在处理读事件的过程中决定不再监听读事件,可以在这里调用remove_handler//但注意:在handle_input中调用remove_handler(READ_MASK)是安全的吗?//根据ACE的规则,在事件处理函数中移除自己(部分事件)是允许的。//例如://if(some_condition){//ACE_Reactor::instance()->remove_handler(get_handle(),ACE_Event_Handler::READ_MASK);//}return0;//返回0表示继续监听,但我们已经移除了读事件,所以下次不会收到读事件了}//...其他部分};```重要:在事件处理函数(如handle_input)中调用remove_handler(READ_MASK)是安全的,因为反应器允许在回调中修改事件注册。另外,如果我们希望移除读事件的同也移除写事件等,可以使用ALL_EVENTS_MASK。引用[1]还提到,在显式拆除可以避免调用handle_close方法:reactor->remove_handler(handler,ACE_Event_Handler::DONT_CALL);但是,注意上面的remove_handler版本有两个参数(句柄和掩码)的版本,它默认会调用handle_close(除非指定DONT_CALL)。然而,当我们移除特定事件(不是整个处理器),不会调用handle_close。因为handle_close是在整个事件处理器被移除才调用的。根据ACE文档:当使用remove_handler(handle,mask),反应器会从反应器的内部表中移除指定的事件类型,但不会删除事件处理器对象,也不会调用handle_close。只有当移除整个事件处理器(即使用ALL_EVENTS_MASK或者使用remove_handler(handler)),才会调用handle_close(除非指定了DONT_CALL)。因此,如果只是移除READ_MASK,那么不会调用handle_close,事件处理器对象仍然存在(可能还处理其他事件)。总结:-注销READ_MASK事件:调用remove_handler(handle,ACE_Event_Handler::READ_MASK)-这不会导致handle_close被调用,也不会影响其他事件。用户可能需要根据实际场景选择方法。注意:在移除事件后,如果事件处理器不再需要,用户应该负责删除它(如果它是动态分配的)?但通常,事件处理器对象的管理由应用负责。反应器不会自动删除事件处理器,除非在移除整个处理器(且没有指定DONT_CALL)在handle_close中删除自己。在引用[3]的示例中,在handle_input中返回-1会导致整个事件处理器被拆除(包括调用handle_close)。在那个示例中,接受器在每次接受一个连接后就把自己移除了,这显然不是常见的做法。常见的是接受器持续监听,而每个连接创建一个新的事件处理器。所以那个示例可能只是为了演示,实际应用可能不同。因此,针对用户的问题,我们给出显式移除READ_MASK的代码示例。注意:以上内容基于引用和ACE的常规用法。由于ACE版本和具体实现可能有差异,建议用户参考官方文档。相关问题:1.在ACE反应器中,如何注册事件处理器?2.事件处理器中的handle_close方法有什么作用?3.如何正确管理ACE_Event_Handler的生命周期?4.在移除事件处理器,DONT_CALL标志的具体影响是什么?</think>### 如何注销 ACE_Event_Handler 中的 READ_MASK 事件 在 ACE 框架中注销 `READ_MASK` 事件主要有两种方法,核心是通过 `ACE_Reactor::remove_handler()` 实现。以下是具体方法和代码示例: --- #### **方法 1:显式注销(推荐)** 直接调用反应器的 `remove_handler()` 方法注销指定事件: ```cpp // 在事件处理器类中 void unregister_read_event() { // 获取当前句柄和反应器实例 ACE_HANDLE handle = this->get_handle(); ACE_Reactor* reactor = ACE_Reactor::instance(); // 注销 READ_MASK 事件 reactor->remove_handler( handle, // 目标句柄 ACE_Event_Handler::READ_MASK // 指定事件类型 ); } ``` **关键参数说明**: - `handle`:通过 `get_handle()` 获取的事件关联句柄(如 socket) - `READ_MASK`:明确指定注销读事件 - **默认行为**:调用 `handle_close()` 清理资源(可通过参数禁用) --- #### **方法 2:隐式自动注销** 在 `handle_input()` 方法中返回负值触发自动注销: ```cpp // 在事件处理器的读回调中 int handle_input(ACE_HANDLE handle) override { // 业务逻辑处理... if (need_unregister) { return -1; // 返回值 <0 触发自动注销 } return 0; // 继续保留事件监听 } ``` **注意**:此方法会触发 `handle_close()` 并**完全移除整个事件处理器**(不限于 `READ_MASK`)[^1]。 --- #### **完整示例代码** ```cpp class My_Handler : public ACE_Event_Handler { public: ACE_HANDLE get_handle() const override { return socket_.get_handle(); // 返回关联的socket句柄 } int handle_input(ACE_HANDLE handle) override { char buffer[1024]; ssize_t n = socket_.recv(buffer, sizeof(buffer)); if (n <= 0) { unregister_read_event(); // 显式注销读事件 return 0; } // 处理数据... return 0; } // 显式注销 READ_MASK void unregister_read_event() { ACE_Reactor::instance()->remove_handler( get_handle(), ACE_Event_Handler::READ_MASK ); } private: ACE_SOCK_Stream socket_; }; ``` --- #### **关键注意事项** 1. **选择性注销**: - 显式调用 `remove_handler(handle, READ_MASK)` 仅注销读事件,其他事件(如 `WRITE_MASK`)不受影响。 - 隐式返回 `-1` 会移除**所有事件**并销毁处理器。 2. **资源清理**: - 默认调用 `handle_close()` 释放资源,可通过添加 `DONT_CALL` 标志跳过: ```cpp reactor->remove_handler(handle, READ_MASK | ACE_Event_Handler::DONT_CALL); ``` 3. **线程安全**: - 在 `handle_*` 方法内部调用 `remove_handler()` 是安全的,反应器已处理同步[^2]。 --- ### 相关问题 1. **事件注销后如何重新注册读事件?** 需重新调用 `reactor->register_handler(handler, READ_MASK)`。 2. **`handle_close()` 方法的作用和实现规范?** 用于资源清理,反应器在注销自动调用(除非显式禁用)[^1]。 3. **如何区分注销单一事件与完整事件处理器?** `remove_handler(handle, READ_MASK)` 仅注销读事件;`remove_handler(handler)` 注销整个处理器。 4. **ACE_Reactor 在多线程环境下的注销安全问题?** 反应器内部使用锁保证线程安全,但需避免在回调外直接操作句柄[^2]。 [^1]: 隐式自动拆除或显式拆除均会触发 `handle_close()` 进行资源清理。 [^2]: 反应器在回调期间已锁定,事件处理器方法内操作是安全的。 [^3]: 事件处理器需正确实现 `get_handle()` 以关联目标句柄。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值