编辑: 无理的喜欢 | 2017-12-17 |
break;
case SIGINT: ACE_DEBUG((LM_DEBUG, You pressed SIGINT \n ));
break;
} return 0;
} };
int main(int argc, char *argv[]) { //instantiate the handler MyEventHandler *eh =new MyEventHandler;
//Register the handler asking to call back when either SIGWINCH //or SIGINT signals occur. Note that in both the cases we asked the //Reactor to callback the same Event_Handler i.e., MyEventHandler. //This is the reason why we had to write a switch statement in the //handle_signal() method above. Also note that the ACE_Reactor is //being used as a Singleton object (Singleton pattern) ACE_Reactor::instance()->
register_handler(SIGWINCH,eh);
ACE_Reactor::instance()->
register_handler(SIGINT,eh);
while(1) //Start the reactors event loop ACE_Reactor::instance()->
handle_events();
} 在上面的例子中,我们首先创建了一个ACE_Event_Handler的子类,在其中我们重载了handle_signal()方法,因为我们想要使用此处理器来处理多种类型的信号.在主函数中,我们对我们的处理器进行实例化,随后调用ACE_Reactor单体(Singleton)的register_handler,指明我们希望在SIGWINCH(终端窗口改变信号)或SIGINT(中断信号,通常是^C)发生时,事件处理器 eh 会被回调.然后,我们通过调用在无限循环中调用handle_events()来启动反应堆的事件循环.无论是发生哪一个事件,反应堆都将自动回调eh->
handle_signal()方法,将引发回调的信号号码、以及siginfo_t结构(有关siginfo_t的更多信息,参见siginfo.h)传给它. 注意程序是怎样使用单体模式(Singleton Pattern)来获取全局反应堆对象的引用的.大多数应用都只需要一个反应堆,因而ACE_Reactor::instance()会确保无论何时此方法被调用,都会返回同一个ACE_Reactor实例(要阅读更多有关单体模式的信息,请见 设计模式 参考文献[VI]). 表6-1显示在ACE_Event_Handler的子类中必须重载哪些方法,以处理不同的事件类型. ACE_Event_Handler中的处理方法 在子类中重载,所处理事件的类型: handle_signal() 信号.当任何在反应堆上登记的信号发生时,反应堆自动回调该方法. handle_input() 来自I/O设备的输入.当I/O句柄(比如UNIX中的文件描述符)上的输入可用时,反应堆自动回调该方法. handle_exception() 异常事件.当已在反应堆上登记的异常事件发生时(例如,如果收到SIGURG(紧急信号)),反应堆自动回调该方法. handle_timeout() 定时器.当任何已登记的定时器超时的时候,反应堆自动回调该方法. handle_output() I/O设备输出.当I/O设备的输出队列有可用空间时,反应堆自动回调该方法. 表6-1 ACE_Event_Handler中的处理方法及其对应事件 6.2.1 事件处理器登记 如我们在上面的例子中所看到的,登记事件处理器、以处理特定事件,是在反应堆上调用register_handler()方法来完成的.register_handler()方法是重载方法,就是说,实际上有若干方法可用于登记不同的事件类型,每个方法都叫做register_handler().但是它们有着不同的特征:它们的参数各不相同.基本上,register_handler()方法采用handle/event_handle元组或signal/event_handler元组作为参数,并将它们加入反应堆的内部分派表.当有事件在handle上发生时,反应堆在它的内部分派表中查找相应的event_handler,并自动在它找到的event_handler上回调适当的方法.有关登记处理器的专用调用的更多细节将在后面的部分进行阐释. 6.2.2 事件处理器的拆除和生存期管理 一旦所需的事件被处理后,可能就无需再让事件处理器登记在反应堆上.因而,反应堆提供了从它的内部分派表中拆除事件处理器的技术.一旦事件处理器被拆除,它就不再会被反应堆回调. 为多个客户服务的服务器是这种情况的一个例子.客户连接到服务器,让它完成一些工作,然后从服务器断开.当有新的客户连接到服务器时,一个事件服务器对象被实例化,并登记到服务器的反应堆上,以处理所有与此客户有关的I/O.当客户断开时,服务器必须将事件处理器从反应堆的分派队列中拆除,因为它将不再进行任何与此客户有关的I/O.在此例中,客户/服务器连接可能会被关闭,使得I/O句柄(UNIX中的文件描述符)变得无效.把这样的死掉的句柄从反应堆里拆除是很重要的,因为,如果不这样做,反应堆将会把此句柄标记为 读就绪 ,并会持续不断地回调此事件处理器的handle_input()方法. 6.2.2.1 从反应堆内部分派表中隐式拆除事件处理器 隐式拆除是更为常用的从反应堆中拆除事件处理器的技术.事件处理器的每个 handle_ 方法都会返回一个整数给反应堆.如果此整数为0,在处理器方法完成后、事件处理器将保持在反应堆上的登记.但是,如果 handle_ 方法返回的整数peer_i().get_handle();