peakzhang 发表于 2008-1-17 18:44:21

ACE Crashes on exit (see very very simple sample code included)

ACE version :
This is ACE version 5.4, released Wed Jan 14 18:45:46 2004.

Visual C++ version 6 SP3.

--- SAMPLE BEGIN ---


#include <ace/Event_Handler.h>
#include <ace/reactor.h>
#include <ace/OS_NS_sys_time.h>

struct Main : public ACE_Event_Handler
{
         int _f;
         int _t1;

      Main() {_f = _t1 = 0;}
         init();
         virtual int handle_timeout(const ACE_Time_Value &tv, const void *arg);

};


Main::init()
{
         _t1 = ACE_Reactor::instance()->schedule_timer(this, (void *) 1, 0, 1);

}


int Main::handle_timeout(const ACE_Time_Value &tv, const void *arg)
{
         static int c = 0;
         printf("t\n");
         if (c++ == 3)
               _f = true;
         return 0;

}


int main(int argc, char* argv[])
{
         Main m;

      m.init();

      while (!m._f)
         {
               ACE_Reactor::instance()->handle_events();
         }

      return 0;

}



--- SAMPLE END ---
ACE crahses after exiting main().

If someone could help ...

Thank you for advance.

peakzhang 发表于 2008-1-17 18:44:32

Dr. Doug 是这样回答的:
The problem here is that you allocate Main m on the stack, so it is
destroyed by the time the Reactor's destructor tries to remove the
event handler.Please see Chapters 3 and 4 of C++NPv2
<www.cs.wustl.edu/~schmidt/ACE/book2/> for information on how to avoid
this problem.

我的问题是:
Reactor在析构时会自动删除(delete)已登记的event handler吗?
如果是的话,如果避免以上问题?
如何让Reactor不自动删除已登记的event handler?

谢谢!

peakzhang 发表于 2008-1-17 18:44:45

追踪源代码,的确会逐个调用每个handle的handle_close(),
你可以自己删除啊,传递:DONT_CALL标志,不会调用handle_close.


ACE_Reactor::instance ()->remove_handler(impl->get_handle (), ACE_Event_Handler::DONT_CALL);

peakzhang 发表于 2008-1-17 18:44:53

导致crash的原因,其实不是堆上分配 OR 栈上分配。我已经做过程序验证,真正的原因是:
程序退出的时候,没有取消timer定时器,这样一来,造成栈错误。

       while (!m._f)
         {
               ACE_Reactor::instance()->handle_events();
         }
//增加一行,不再出错。
       ACE_Reactor::instance()->cancel_timer(&m);

peakzhang 发表于 2008-1-17 18:45:02

我做实验验证,是这样的:
在程序退出时,由于m已经析构,但reactor此时又调用了m的handle_close,导致程序crash掉

如果上述m在堆上分配,程序就不会crash掉,但会导致内存泄漏

peakzhang 发表于 2008-1-17 18:45:08

一样有问题。内存堆在程序退出的时候,一样废除,只是代码还能访问而已。
handle_close默认的实现,只是简单的返回,不会造成这个错误。
你加上取消timer,就不会出错了。

peakzhang 发表于 2008-1-17 18:45:14

在windows平台下,ace中的reactor 在移除事件句柄时会有一个延时,即:如果你在栈上分配一个ACE_EventHandler对象,经常是当你退出了这个变量的作用阈,对象已经被析构后,事件句柄才从reactor内部的句柄列表中移除。这时如果调用对象的handle_close方法,就会导致异常退出.这种coredump行为是不可预期的,有时候根本不会出现。需要指出的是,有时候即使你在remove handler的时候传入了DONT_CALL标记,这个行为还是会发生。

   所以在windows平台下,event_handler的实例应该是new出来的,然后在handle_close方法使用delete this进行析构。以保证在调用handle_close方法的时候对象仍然存在。
在unix/linux平台下,则不存在这个问题。


上面的解释在C++NPv2 有,忘记在哪一页了,你可以翻翻。

置于这里的定时器没有释放,算是另外一个错误吧。

xbbbbb 发表于 2009-8-30 19:12:24

re:: ACE_Reactor::instance ()->remove_handler(impl->get_handle (), ACE_Event_Handler::DONT_CALL);

如果crash at ACE_WFMO_Reactor_Handler_Repository::make_changes_in_current_infos (void) 。。。
。。。。L771 event_handler->handle_close (handle, masks);
跟踪,L680       while (i < this->max_handlep1_) 中 max_handlep1 不随remove_handler操作-1,
如果event_handler被手动释放,则非法指针

remove_handler和register_handler同时加上 DONT_CALL,则没有问题

ACE_Reactor::instance ()->register_handler(impl->get_handle (), ACE_Event_Handler::DONT_CALL);
。。。。。。
ACE_Reactor::instance ()->remove_handler(impl->get_handle (), ACE_Event_Handler::DONT_CALL);

[ 本帖最后由 xbbbbb 于 2009-8-30 19:16 编辑 ]
页: [1]
查看完整版本: ACE Crashes on exit (see very very simple sample code included)