Heorhiy
Heorhiy

Reputation: 190

shared_ptr refcounter implementation thead safety

This is the implementation of shared_ptr from VisualStudio 2017

MSDN states that refcounting block is thread safe. I wonder, what if in thread1 we check rep for null (if (_Other._Rep) //1),
then thread2 check rep for null, decrese refcounter to 0 and call _Destroy(); after that thread1 tryes to increment deleted ref counter. Isn't it a problem or where I have misunderstanding?

void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
{   // implement shared_ptr's (converting) copy ctor
    if (_Other._Rep) //1
    {
        _Other._Rep->_Incref();
    }

    _Ptr = _Other._Ptr;
    _Rep = _Other._Rep;
}

void _Decref()
  { // decrement reference count
    if (_Rep) //2
    {
        _Rep->_Decref(); //3
    }
  }

void _Decref()
{   // decrement use count
    if (_MT_DECR(_Uses) == 0)
    {   // destroy managed resource, decrement weak reference count
        _Destroy();
        _Decwref();
    }
}

update:

 thread1: ctor (_Copy_construct_from)
  thread1: if (_Other._Rep) 
  thread2 _Decref
  thread2 _Rep->_Decref();
  thread2 _Destroy();
  thread1 _Other._Rep->_Incref(); // but object is already destroed 

Upvotes: 0

Views: 146

Answers (1)

walnut
walnut

Reputation: 22152

The code you are showing in the first block is part of the copying or converting constructor, e.g. you are calling something along the line of:

std::shared_ptr<A> some_shared_ptr = some_other_shared_ptr;

When the thread executes the line either some_other_shared_ptr is not currently owning any object or it is owning an object. If it is owning an object, then it will keep owning the object during the execution of that statement. Therefore the reference count of the owned object is at least one and cannot become zero and the object will not be destroyed while the statement executes.

If another thread destroys or modifies (e.g. by reseting it) the some_other_shared_ptr object itself potentially while the other thread executes the statement, then the program has a data race and undefined behavior. The shared_ptr object itself is not atomic (and even if it were, destroying it potentially before accessing it in another thread would cause undefined behavior). It is only thread safe in the sense that additional owning copies can be made and destroyed freely across threads without causing data races, the reference count to the owned object becoming inconsistent or the object being destroyed multiple times.

Upvotes: 3

Related Questions