C ++ 11 shared_ptr在多线程下多次释放

问题描述

在g ++ 4.8.5编译下,发现对sharedptr的不当使用会导致对shared_ptr的多次破坏。

假码:

#include<memory>

class Demo
{
public:
    ~Demo()
    {
        // Do something and cost some milliseconds
    }    
};
typedef std::shared_ptr<Demo> DemoPtr;

DemoPtr global_demo;
DemoPtr instance() {return global_demo;}

// Main thread
int main()
{
    global_demo = std::make_shared<Demo>();
    // Do something
}

// Thread A
void thread_func()
{
    // Do something
    
    if(instance() != nullptr)
    {
        // Do something
    }

    // Do something
}

当主线程结束时,global_demo引用计数减少为0,并且global_demo开始被破坏。销毁global_demo时,线程A调用instance()进行判断,这导致global_demo的引用计数再次增加一,然后释放局部变量时,引用计数再次减小为0,从而导致对global_demo指向的对象的销毁。再次调用该函数。

查看gcc源代码:

//*************__shared_count***************//
__shared_count&
operator=(const __shared_count& __r) noexcept
{
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
    if (__tmp != _M_pi)
    {
        if (__tmp != 0)
            __tmp->_M_add_ref_copy();
        if (_M_pi != 0)
            _M_pi->_M_release();
        _M_pi = __tmp;
    }
    return *this;
}

//************_Sp_counted_base*****************//
void
_M_add_ref_copy()
{ __gnu_cxx::__atomic_add_dispatch(&_M_use_count,1); }

那么,这是一个GCC错误吗?

在这种情况下,我应该使用std :: weak_ptr解决此问题吗? 那么,我的instance()方法代码是这样的吗?

DemoPtr instance() 
{
    std::weak_ptr<Demo> w(global_demo);
    if(!w.expired())
    {
        return w.lock();
    }
    return nullptr;
}

解决方法

那么,这是一个GCC错误吗?

不。这是程序中的错误:

global_demo被破坏

线程A调用instance()

DemoPtr instance() {return global_demo;}

您正在复制生命周期已结束(被破坏)的对象的副本(return global_demo;)。该程序的行为是不确定的。


在这种情况下,我应该使用std :: weak_ptr解决此问题吗?

这不能修复该错误。您必须做的是在从main返回之前,加入所有依赖静态变量的线程。 从技术上讲,可以在静态对象的析构函数中在main返回之后加入线程,只要保证该对象在依赖的静态对象之前被销毁即可。但是,祝你好运。


对于某些线程,我无法控制结束。

然后,您必须避免在那些线程中使用任何静态变量。在示例情况下,创建global_demo的线程本地副本,并在线程内使用它。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...