我正在阅读std::shared_ptr of libstdc++的实现,我注意到libstdc++有三种锁定策略:_S_single、_S_mutex和_S_atomic (参见这里),而锁策略会影响类_Sp_counted_base (参考和发布)的专业化。
下面是代码片段:
_M_release_last_use() noexcept
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
_M_dispose();
// There must be a memory barrier between dispose() and destroy()
// to ensure that the effects of dispose() are observed in the
// thread that runs destroy().
// See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
if (_Mutex_base<_Lp>::_S_need_barriers)
{
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
-1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
_M_destroy();
}
}
template<>
inline bool
_Sp_counted_base<_S_mutex>::
_M_add_ref_lock_nothrow() noexcept
{
__gnu_cxx::__scoped_lock sentry(*this);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
{
_M_use_count = 0;
return false;
}
return true;
}
我的问题是:
发布于 2021-12-09 12:38:34
其中一些问题在文档和您引用的代码中显示的URL中得到了回答。
是。
不,那不可能发生。当_M_release_last_use()
开始执行_M_weak_count >= 1
时,_M_destroy()
函数在_M_weak_count
减少之后才会被调用,因此_M_ptr
在_M_dispose()
调用期间仍然有效。如果_M_weak_count==2
和另一个线程在运行_M_release_last_use()
的同时递减它,那么就会有一个竞赛来查看哪个线程首先减少,因此您不知道哪个线程将运行_M_destroy()
。但是无论是哪一个线程,_M_dispose()
在_M_release_last_use()
做缩减之前就已经完成了。
内存屏障的原因是_M_dispose()
调用删除器,后者运行用户定义的代码。该代码可能会产生任意的副作用,影响程序中的其他对象。_M_destroy()
函数使用operator delete
或分配器释放内存,这也可能产生任意副作用(如果程序已经替换了operator delete
,或者shared_ptr
是用自定义分配器构造的)。存储器屏障确保删除器的效果与去分配的效果同步。库不知道这些效果是什么,但没关系,代码仍然确保它们同步。
他们不是。
https://stackoverflow.com/questions/70289544
复制相似问题