首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 计算机考试 > 等级考试 > 复习指导 >

Event_Handler在程序退出前应该自己关闭

2009-02-07 
Event_Handler

    在程序退出的【注】,我们往往不会自己关闭Event_Handler,而寄希望Reactor 的清理。但是实际情况会复杂很多。使用的时候必须当心。
  【注】是否要在退出的时候清理所有分配的内存?在普通的操作系统中,程序的退出会回收所有的分配内存。所以很多人会逃避在最后阶段的清理分配的内存。但是这实在不是一个良好的喜欢。一方面对于很多OS(比如嵌入系统)不会回收内存资源,一些内核资源(UNIX)也不会在进程退出后释放,编程就应该要养成清理的好习惯,更何况不进行释放在内存检查的软件一般会报错,如果不清理会干扰我们对于内存泄露的定位。
  1 Reactor的close可能不会关闭Event_Handler
  理论上讲,ACE_Reactor提供了一个close函数,所有的Event_Handler应该统一在这个函数进行关闭。
  ACE_Reactor采用的是模式,封装了不同Reactor的实现。这些实现的close函数未存在一定的差异性。就我的阅读和尝试来看,Select_Reactor在close函数关闭了所有的IO句柄相关的Event_Handler,而Dev_Poll_Reactor的close实现就没有关闭。
  Select_Reactor的close代码。
  template <class ACE_SELECT_REACTOR_TOKEN> int
  ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::close (void)
  {
  ……
  //在handler_rep的close函数会关闭所有的register的句柄的handler,调用他们的
  //handle_close函数
  this->handler_rep_.close ();
  Dev_Poll_Reactor的close的调用了函数ACE_Dev_Poll_Reactor_Handler_Repository::close,而后有逐步调用了unbind_all,remove_reference。
  //close会经过多级调用到ACE_Dev_Poll_Reactor_Handler_Repository:: unbind_all
  //unbind被unbind_all函数调用decr_refcnt == true
  int
  ACE_Dev_Poll_Reactor_Handler_Repository::unbind (ACE_HANDLE handle,
  bool decr_refcnt)
  {……
  // remove_reference函数没有调用handle_close,而是减去了引用计数
  if (decr_refcnt)
  this->handlers_[handle].event_handler->remove_reference ();
  ……
  }
  ACE_Event_Handler::Reference_Count
  ACE_Event_Handler::remove_reference (void)
  {
  //如果打开了引用计数,则使用应用计数方式管理方式。但是代码默认不采用应用计数模式
  //所以下面的代码都无法执行
  if (reference_counting_required)
  {
  //减去引用计数
  Reference_Count result =
  --this->reference_count_;
  //如果已经没用引用个数了,删除自己。
  if (result == 0)
  delete this;
  }
  可以看到ACE_Event_Handler的代码默认不采用应用计数模式,(eference_counting_required默认为DISABLED)而Dev_Poll_Reactor却非要使用引用计数模式去清理Event_Handler。
  我对Dev_Poll_Reactor为什么要设计成这样表示不解。也对Dev_Poll_Reactor提交过BUG,但是Dev_Poll_Reactor的开发者不认为这样有什么不妥,本人E文羞涩,无法说服具体的开发人员,不过在提交BUG时,居然得到了Douglas反馈(他开始时认同我的看法),对于他们的执着和认真还是表示敬仰。
  2 可能会导致重复释放引发Coredump
  这个问题是在工作中调试一个BUG出现的。
  在测试一个服务器的时候发现Coredump发生kill进程,让其退出在之后,会出现Coredump文件。Coredump显示出现问题的地方在。
  #1 0x0805bc7b in ~ACE_Timer_Heap_T (this=0x82d3ec8) at /usr/local/ACE_wrappers/ace/Timer_Queue_T.cpp:442
  #2 0x0805b86d in ~ACE_Singleton (this=0x82cca70) at egg_application.cpp:52
  #3 0x08056785 in ACE_Singleton<EggSvrdAppliction, ACE_Null_Mutex>::cleanup (this=0x82dfb90)
  由于希望改变ACE_Time_Queue的特性(数量),我替换Reactor的默认Time_Queue,所以必须自己销毁自己管理的TimeQueue。而在外部最后销毁的时候出现Coredump。由于和Time_Queue相关,我检查了所有的Timer相关的Event_handler,发现有一个Event_handler没有自己主动调用handler_close释放,这个Event_handler只有定时器,没有注册任何IO事件。修改代码为主动释放后,再次测试就发现Coredump的问题得到解决。
  检查了一下原有代码堆栈的调用顺序,找到了问题原因。
  (1)ACE_Reactor::close,实际调用ACE_Select_Reactor::close
  (2) Select_Reactor::close 尝试关闭所有的IO句柄相关的Event_handler,但由于Time_Queue是外部传入的参数,所以不清理Time_Queue。
  (3)Time_Queue清理,Time_Queue的析构函数被调用,Time_Queue的析构函数会释放所有的定时器相关的Event_handler。而他的释放还会调用hanlder_close。但是这是Reactor对象已经销毁了。所以造成了Coredump。
  注意由于Reactor的封装了Event_handler定时器,IO句柄,Notify机制等回调接口。所以Event_handler可能只关联到IO句柄,也可能只关联定时器,同时Reactor的模型决定了他的内部管理是复杂的。而在释放的过程中很可能会发生交错的问题,而,像上面问题的Event_handler就只关联的定时器,所以在Reactor的close的时候没有关闭。从而导致在后面的清理工作中产生时序问题。
  最简单的方式还是自己在程序退出前清理释放所有的Event_handler.再调用Reactor的close。

 

3COME考试频道为您精心整理,希望对您有所帮助,更多信息在http://www.reader8.com/exam/

热点排行