【发布时间】:2022-01-14 06:18:02
【问题描述】:
我正在阅读 libstdc++ 的 std::shared_ptr 的实现,我注意到 libstdc++ 具有三个锁定策略:_S_single、_S_mutex 和 _S_atomic(请参阅here),并且锁定策略会影响类的专业化_Sp_counted_base(_M_add_ref 和 _M_release)
下面是sn-p的代码:
_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;
}
我的问题是:
- 使用 _S_mutex 锁定策略时,__exchange_and_add_dispatch 函数可能只保证原子性,但不能保证完全隔离,对吗?
- 因为 1,'__atomic_thread_fence (__ATOMIC_ACQ_REL)' 的目的是确保当线程 A 调用 _M_dispose 时,没有线程将调用 _M_destory(这样线程 A 永远无法访问被破坏的成员(例如:_M_ptr)函数“_M_dispose”?
- 最让我困惑的是,如果 1 和 2 都正确,那为什么在调用 '_M_dispose' 之前不需要添加线程栅栏呢? (因为 _Sp_counted_base 和 _Sp_counted_base 管理的对象在引用计数降为零时本身也有同样的问题)
【问题讨论】:
-
没有glibc++这种东西
-
@Jonathan Wakely 对不起,应该是 libstdc++,我更正了
标签: c++ multithreading std libstdc++ memory-barriers