如何使用原子操作实现 std::weak_ptr::lock ?

2024-06-20

最近尝试用C实现原子引用计数器,所以参考了STL中std::shared_ptr的实现,对weak_ptr::lock的实现很困惑。 执行compare_and_exchange时,clang指定了memory_order_seq_cst,g++指定了memory_order_acq_rel,MSVC指定了memory_order_relaxed。 我认为 memory_order_relaxed 已经足够了,因为如果 user_count 非零,则不需要同步数据。 我不是这方面的专家,有人可以提供一些建议吗?

以下是代码片段:

MSVC https://github.com/microsoft/STL/blob/main/stl/inc/memory#L1084

    bool _Incref_nz() noexcept { // increment use count if not zero, return true if successful
        auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);
#ifdef _M_CEE_PURE
        long _Count = *_Atomic_address_as<const long>(&_Volatile_uses);
#else
        long _Count = __iso_volatile_load32(reinterpret_cast<volatile int*>(&_Volatile_uses));
#endif
        while (_Count != 0) {
            const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);
            if (_Old_value == _Count) {
                return true;
            }

            _Count = _Old_value;
        }

        return false;
    }

铿锵/libcxx https://github.com/llvm/llvm-project/blob/main/libcxx/src/memory.cpp#L119

__shared_weak_count*
__shared_weak_count::lock() noexcept
{
    long object_owners = __libcpp_atomic_load(&__shared_owners_);
    while (object_owners != -1)
    {
        if (__libcpp_atomic_compare_exchange(&__shared_owners_,
                                             &object_owners,
                                             object_owners+1))
            return this;
    }
    return nullptr;
}

海湾合作委员会/libstdc++ https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L277

 template<>
    inline bool
    _Sp_counted_base<_S_atomic>::
    _M_add_ref_lock_nothrow() noexcept
    {
      // Perform lock-free add-if-not-zero operation.
      _Atomic_word __count = _M_get_use_count();
      do
    {
      if (__count == 0)
        return false;
      // Replace the current counter value with the old value + 1, as
      // long as it's not changed meanwhile.
    }
      while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
                      true, __ATOMIC_ACQ_REL,
                      __ATOMIC_RELAXED));
      return true;
    }

我正在尝试自己回答这个问题。

The 标准规格 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf只说weak_ptr::lock应该作为原子操作执行,但没有更多关于内存顺序的信息。这样不同的线程就可以直接并行调用weak_ptr::lock,而不需要任何竞争条件,并且当发生这种情况时,不同的实现提供不同的memory_order。 但不管怎样,上面的实现都是正确的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用原子操作实现 std::weak_ptr::lock ? 的相关文章

  • 我使用 tm/mktime 是否错误,如果没有,有解决方法吗?

    我认为下面的程序应该输出从公元 1 年到 1970 年每年第一天到 1970 年的秒数 前面是time t在编译它的系统上 CHAR BIT是一个宏 所以我认为你不能只是复制编译后的可执行文件并假设它是正确的 尽管实际上一切都使用 8 位c
  • clang 3.0 + libc++ 中的 std::async 不起作用?

    我刚刚在我的 ubuntu 10 04 上编译并安装了 clang llvm 3 0 并且还从 svn 编译并安装了 libc 由于 libc 中的状态显示线程支持已完成 因此我想尝试 std async 所以我按照安东尼 威廉姆斯 Ant
  • MSVC - 如何确定类型是否必须移动? [复制]

    这个问题在这里已经有答案了 我似乎遇到了编译器 库错误的问题 当我尝试时 include
  • Visual C++ MFC 中窗口启动时的事件顺序

    假设我有一个从 CWnd 派生的类 它具有事件处理函数OnPaint OnCreate and OnSize 如您所知 所有这些都是在窗口启动时发生的 但我想看看它们之间的顺序是什么 例如 当我在其中一个中设置断点时 在结束函数后 控制不会
  • 子类化 QVector

    这是我的问题 我想对 QVector 进行子类化 以便添加一些特定于我的上下文的函数 天真的方法是 class ClassVector public QVector
  • 是否有与 gcc --kill-at 等效的 Visual C++?

    也就是说 DLL 名称末尾有一个额外的 8 这会造成问题 显然 在 gcc 中使用 kill at 标志可以解决这个问题 但我找不到任何类似的 MSVC 建议 编辑 更多信息 我试图让 C JNI dll 工作 但我总是得到 线程 Thre
  • 不使用 DAO 压缩 Microsoft Access 数据库

    我用CDatabase类开一个ACCDB访问数据库 司机是 T Microsoft Access Driver mdb accdb 我可以打开并使用数据库 已经这样做很多年了 if DatabaseExist m strMDBPath AJ
  • 这个程序有什么问题?

    include
  • 如何更新 C++ dll 而无需将 exe 与 lib 文件重新链接?

    首先 我指的是 Windows 环境和 VC 编译器 我想要做的是重建 Vc dll 并保持与已链接到 lib 的 exe 的兼容性 而无需重建 exe 或使用 LoadLibrary 动态加载 dll 换句话说 有没有办法向 dll 添加
  • std::deque 的内存开销到底是怎么回事?

    我正在研究一种使用外部排序算法std queue并且必须仔细限制其内存使用 我注意到在合并阶段 使用了几个std queues 固定长度 我的内存使用量增加到我预期的大约 2 5 倍 自从std queue默认情况下使用std deque作
  • _addcarry_u64 和 _addcarryx_u64 与 MSVC 和 ICC

    MSVC 和 ICC 都支持内在函数 addcarry u64 and addcarryx u64 根据英特尔的内在指南 https software intel com sites landingpage IntrinsicsGuide
  • 如何在 Visual C++ 中读取版本资源

    我在 C 项目的资源中有一个版本资源 其中包含版本号 版权和构建详细信息 有没有一种简单的方法可以在运行时访问它来填充我的帮助 关于对话框 因为我目前正在维护此信息的单独常量值 理想情况下 该解决方案应适用于 Windows CE mobi
  • MFC 中标题栏上的关闭按钮

    在基于 Vc 6 0 对话框的 MFC 应用程序中 我不希望我的用户通过按窗口本身右上角的按钮 X 以及 Alt F4 来关闭窗口 我想显示一个消息框 你真的想关闭应用程序吗 如果用户单击 确定 按钮 则应用程序必须关闭 否则 如果用户单击
  • C++使用太多CPU

    好的 我正在创建一个游戏 但它使用了太多的 cpu 但它没有使用太多的内存 cpu确实增加和减少 我的游戏中有太多计时器 当我不再使用计时器时 我会杀死计时器 因此这应该会导致问题 但我认为导致问题的原因是我的消息队列中有太多消息 我有一台
  • 非实例化模板成员的编译时错误而不是链接时错误

    我有模板类ItemContainer这实际上是整个容器系列的外观 具有不同的功能 如排序 索引 分组等 实施细节隐藏在cpp 使用 pimpl 习惯用法和显式实例化的文件 模板仅使用定义容器实际行为的众所周知的有限实现类集进行实例化 主模板
  • 在 VC++ 中从 MSI(数据库)查找文件路径

    我需要计算 MSI 中文件的相对路径 目前 我正在查询File表获取FileName对应的Component 然后 我使用此组件来查询组件表并找到 Directory 接下来 我使用这个Directory 来查询Directory表并找到D
  • 为什么 C++ CLI 对于托管类型没有默认参数?

    以下行有错误Default argument is not allowed public ref class SPlayerObj private void k int s 0 ERROR 为什么 C 对托管类型没有默认参数 我想知道是否有
  • 使用 openCV 检测 ROI

    我正在做一项工作 我必须找到感兴趣的区域 ROI 然后对图像执行阈值 由于我不是计算机领域的 所以我遇到了一些困难 我开始尝试通过以下代码找到投资回报率 code string filename 2011 06 11 09 3A12 3A1
  • VC++致命错误LNK1168:无法打开filename.exe进行写入

    Suddenly my Visual Studio Express 2010 C stopped rebuilding my project When I first hit F7 the project builds and runs f
  • 安装/编译 pylzma(lzma python 绑定)

    我已经向作者提出了这个问题website http www joachim bauch de projects pylzma comment page 1 comment 5211 但我想我也可以在这里问 我一直在尝试使用以下设置安装 py

随机推荐