一个不起眼的手误,让我调了半小时,大家最好先别看解析部分,自己练一下眼里吧。
运行是报段错误:
(3077573488) starting up
(3077573488) is exiting
段错误
下面给出错误代码:
1 #include <ace/Task.h>
2 #include <ace/Log_Msg.h>
3 #include <ace/Thread_Manager.h>
4
5 class ExitHandler : public ACE_At_Thread_Exit {
6 public:
7 virtual void apply (void) {
8 ACE_DEBUG ((LM_DEBUG,
9 ACE_TEXT ("(%t) is exiting\n")));
10 // Shutdown all devices.
11 }
12 };
13
14 class MyThread : public ACE_Task_Base {
15 public:
16 MyThread (ExitHandler &eh) : eh_(eh) {}
17 virtual int svc () {
18 ACE_DEBUG ((LM_DEBUG,
19 ACE_TEXT ("(%t) starting up\n")));
20
21 this->thr_mgr ()->at_exit (eh_);
22
23 // Do something.
24 ACE_OS::sleep (1);
25
26 // Forcefully exit ();
27 ACE_Thread::exit ();
28
29 // Not reached.
30 return 0;
31 }
32 private:
33 ExitHandler eh_;
34 };
35
36
37 int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) {
38 ExitHandler eh;
39
40 MyThread thread (eh);
41 thread.activate ();
42
43 ACE_Thread_Manager::instance ()->wait ();
44 return 0;
45 }
解析:
第33行应该声明为引用,即
33 ExitHandler &eh_;
出现段错误的原因:
原因在于ACE_At_Thread_Exit的构造函数和析构函数
默认够在函数:
ACE_At_Thread_Exit::ACE_At_Thread_Exit (void)
: next_ (0),
td_ (0),
was_applied_ (false),
is_owner_ (true)
{
}
析构函数:
ACE_At_Thread_Exit::~ACE_At_Thread_Exit (void)
{
this->do_apply ();
}
ACE_At_Thread_Exit::do_apply()函数的定义:
void ACE_At_Thread_Exit::do_apply (void)
{
if (!this->was_applied_ && this->is_owner_)
td_->at_pop();
}
可以看到,在默认构造函数中,was_applied_初始化为false,is_owner_初始化为true,而td_初始化为空指针。如果我们使用默认构造函数实例化了一个ACE_At_Thread_Exit类(或其子类)的实例,如果此实例没有被使用,则在实例销毁时将调用td_->at_pop()函数,由于td_为空指针,此行调用将会报段错误。
如果ACE_At_Thread_Exit类的实例被应用到某个ACE_Thread_Manager,则线程退出时将会设置was_applied_为false,这样析构函数中将不再调用td->at_pop()函数。
结论:这应该是ACE的一个bug吧,一个不能随便实例化的类,太危险了,使用时需格外小心。