lundi 17 août 2020

C++11 shared_ptr released multiple times under multithreading

Under g++ 4.8.5 compiling, it is found that improper use of sharedptr will cause multiple destruction of shared_ptr.

Fake code:

#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
}

When the main thread ends, the global_demo reference count is reduced to 0, and global_demo begins to be destructed. When global_demo is being destructed, thread A calls instance() and makes a judgment, which causes the reference count of global_demo to increase by one again, and then when the local variable is released, the reference count is reduced to 0 again, resulting in the destruction of the object pointed to by global_demo The function is called again.

View gcc source code:

//*************__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); }

So, this is a GCC bug?

Should I use std::weak_ptr to solve this problem in this case? So, my instance() method code like this?

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

Aucun commentaire:

Enregistrer un commentaire