shared_ptr refcounter реализация безопасности - PullRequest
0 голосов
/ 28 января 2020

Это реализация shared_ptr из VisualStudio 2017

MSDN утверждает, что блок повторного монтирования является потокобезопасным. Интересно, что если в thread1 мы проверяем rep на null (if (_Other._Rep) //1),
, тогда thread2 проверяет rep на null, уменьшает refcounter до 0 и вызывает _Destroy(); после того, как этот thread1 пытается увеличить удаленный счетчик ref. Разве это не проблема или где у меня возникло недоразумение?

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();
    }
}

обновление:

 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 

1 Ответ

3 голосов
/ 28 января 2020

Код, который вы показываете в первом блоке, является частью конструктора копирования или преобразования, например, вы вызываете что-то вроде:

std::shared_ptr<A> some_shared_ptr = some_other_shared_ptr;

Когда поток выполняет строку, либо some_other_shared_ptr в настоящее время не владеет каким-либо объектом или владеет объектом. Если он владеет объектом, он будет продолжать владеть объектом во время выполнения этого оператора. Поэтому счетчик ссылок на принадлежащий объект равен по крайней мере единице и не может стать нулем, и объект не будет уничтожен во время выполнения оператора.

Если другой поток уничтожает или изменяет (например, путем его сброса), some_other_shared_ptr потенциально сам объект, в то время как другой поток выполняет оператор, тогда программа имеет гонку данных и неопределенное поведение. Сам объект shared_ptr не является атомом c (и даже если бы он был, уничтожение его перед доступом к нему в другом потоке вызвало бы неопределенное поведение). Он безопасен только для потоков, в том смысле, что дополнительные собственные копии можно создавать и уничтожать в разных потоках, не вызывая скачки данных, подсчет ссылок на принадлежащий объект становится несовместимым или объект уничтожается несколько раз.

...