2013-08
猜一下这个代码的输出
class Guard
{
public:
~Guard()
{
cout<<"guard destructing"<<endl;
}
};
class Bar
{
public:
~Bar()
{
cout<<"bar destructing"<<endl;
}
};
class Foo
{
public:
Bar b;
~Foo()
{
Guard g;
cout<<"foo destructing"<<endl;
}
};
void main(int argc,char **argv)
{
Foo b;
}
输出
foo destructing
guard destructing
bar destructing
这个例子说明:析构函数体执行完后,然后析构栈变量,最后开始析构成员变量。
我们真实代码中不是空荡荡的Guard类,,真实代码是这样的:
LocalLicense::~LocalLicense()
{
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_CommonMutex);
......
LocalLicense::xxxxx()
{
ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_CommonMutex);
......
用ACE_Guard来包装mutex锁,可以保证锁的自动释放,这是我们常用的。这里试图用一个锁来同步析构函数和成员方法,这样就有问题了。结合上个例子:当栈变量ACE_Guard被析构后,锁已经释放,然后才开始析构局部变量,此时成员函数可以获得锁并继续执行,如果成员函数也访问同一个局部变量(此时可能正在被析构),结果就是数据不一致,严重的可能导致coredump,挂死。
写了一个例子来模拟,见附件,自己用main方法调用其中的guard_in_destructor,在linux和windows上发生coredump,solaris上挂住
- 关于解决方法
参考网上的一篇文章《当析构函数遇到多线程──C++ 中线程安全的对象回调》。里边推荐了使用shared_ptr,还有很多注意事项。
shared_ptr这个不能完全套用到项目中,新开发的可以参考这样写,但我们实际解决方法需要因地制宜,比如用土办法,锁然后加if(xx!=null)。否则实际要改动的可能很多,风险更大。
网友评论