首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >_Lock_policy在libstdc++中的混淆

_Lock_policy在libstdc++中的混淆
EN

Stack Overflow用户
提问于 2021-12-09 11:58:03
回答 1查看 258关注 0票数 0

我正在阅读std::shared_ptr of libstdc++的实现,我注意到libstdc++有三种锁定策略:_S_single、_S_mutex和_S_atomic (参见这里),而锁策略会影响类_Sp_counted_base (参考发布)的专业化。

下面是代码片段:

代码语言:javascript
运行
复制
_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;
   }

我的问题是:

  1. 当使用_S_mutex锁定策略时,__exchange_and_add_dispatch函数可能只保证原子性,但不能保证它被完全隔离,对吗?
  2. 因为1,“__atomic_thread_fence(__ATOMIC_ACQ_REL)”的目的是确保当线程A调用_M_dispose时,没有线程会调用_M_destory (这样线程A就永远无法访问函数'_M_dispose‘中被破坏的成员(例如:_M_ptr)?
  3. 最让我困惑的是,如果1和2都是正确的,那么为什么在调用'_M_dispose‘之前不需要添加线程围栏?(因为当引用计数降到零时,_Sp_counted_base和_Sp_counted_base本身管理的对象也有相同的问题)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-09 12:38:34

其中一些问题在文档和您引用的代码中显示的URL中得到了回答。

  1. 当使用_S_mutex锁定策略时,__exchange_and_add_dispatch函数可能只保证原子性,但不能保证它被完全隔离,对吗?

是。

  1. 因为1,“__atomic_thread_fence(__ATOMIC_ACQ_REL)”的目的是确保当线程A调用_M_dispose时,没有线程会调用_M_destory (这样线程A就永远无法访问函数'_M_dispose‘中被破坏的成员(例如:_M_ptr)?

不,那不可能发生。当_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是用自定义分配器构造的)。存储器屏障确保删除器的效果与去分配的效果同步。库不知道这些效果是什么,但没关系,代码仍然确保它们同步。

  1. 最让我困惑的是,如果1和2都是正确的,

他们不是。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70289544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档