锁不住的析构函数

2023-06-07  本文已影响0人  塔塔斯坦

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)。否则实际要改动的可能很多,风险更大。

上一篇 下一篇

猜你喜欢

热点阅读