【问题标题】:Checking for sole ownership of shared_ptr检查 shared_ptr 的唯一所有权
【发布时间】:2015-01-23 21:18:45
【问题描述】:

我经常想查看shared_ptr 是否是共享对象的唯一所有者。在销毁最后一个 shared_ptr 之前传递行为会很方便,而不是在销毁之后必须这样做(我的特定用例是通过在销毁之前用另一个 shared_ptr 拯救弱指针来处理弱指针的保存。在销毁开始之后,救他们为时已晚)。

C++11[草案] 20.7.2.1.4:

为了确定是否存在数据竞争,成员 函数只能访问和修改 shared_ptr 和 weak_ptr 对象本身,而不是它们所指的对象。改变在 use_count() 不反映可以引入数据的修改 比赛。

This question 澄清了我对p.use_count() == 1 引起数据竞争的担忧。但是,我仍然不相信以我想要的方式使用它是安全的。

在单线程世界中,如果use_count() 返回 1,那么您就知道您是该对象的最后一个所有者。在您避免数据竞争的多线程世界中,use_count() of 1 似乎是合理的,足以确保您是唯一的所有者,但我在尝试从规范中获得这一点时遇到了令人沮丧的时间。我不知道是否存在允许 use_count 为 1 的漏洞,即使另一个线程上存在另一个 shared_ptr。另一方面,use_count 的定义可能会变成 goo 似乎令人沮丧,因为我将 shared_ptr 交给了另一个线程。

根据规范的规则,我是否会遇到use_count() 为 1,但我不是唯一所有者的情况?我认识到,由于比赛,use_count 为 2 并不明确表示我正在共享(在我在此线程上调用 use_count 后,另一个线程可能会释放我的对象),但我对另一个方向感兴趣,一旦我看到use_count 的 1 个。

作为第二个相关问题:同样的规则是否适用于unique,这似乎是为我想要的实现量身定制的,但没有关于线程安全的任何额外声明?


编辑:响应我得到的答案,我感兴趣的情况是 shared_ptr 我们正在调用 unique_count 只能由单个线程访问,所以我这样做了不用担心任何其他线程成功复制它......他们必须找到自己的shared_ptr来复制!

【问题讨论】:

  • 请注意,您不需要另一个线程来复制您要发布的shared_ptr,但是另一个线程复制一个shared_ptr 或创建一个shared_ptr 就足够了weak_ptr 与您要发布的shared_ptr 共享所有权。正如你所说的,周围有weak_ptrs,所以@Barry 指出use_count 可能返回1 是正确的,但是在看到该值之后,另一个线程可能已经使用weak_ptr 来创建另一个引用。

标签: c++11 thread-safety smart-pointers race-condition


【解决方案1】:

如果有可能存在一个weak_ptr 指向与您的单个shared_ptr 相同的控制块,并且如果另一个线程可能将该weak_ptr 转换为shared_ptr,那么您的线程可能会观察到一个use_count() == 1,但是当它可以使用该信息做任何事情时,另一个线程可能会从weak_ptr 构造一个新的shared_ptr,将use_count 增加到2。

即使没有weak_ptrs,如果有多个线程对您的shared_ptr 具有读取权限(例如说它是全局的),那么在您观察use_count() == 1 之后,另一个线程可能会复制它。

如果任何其他线程都无法访问您的shared_ptr,并且其他线程不可能将weak_ptr 转换为shared_ptr,那么use_count() == 1 是可以安全依赖的。

【讨论】:

    【解决方案2】:

    当然。即使指定 use_count()unique() 都是原子的,但它不是:

    long use_count() const noexcept;
    返回:shared_ptr 对象的数量,包括 *this,与 *this 共享所有权,或 0 当*this 为空时。
    [注意:use_count() 不一定有效。—结束注]

    bool unique() const noexcept;
    返回:use_count() == 1
    [注意:unique() 可能比 use_count() 快。如果您使用unique() 来实现复制 写,get() == nullptr时不要依赖具体值。 ——尾注]

    没有什么可以阻止这样的事情发生:

    std::shared_ptr<Foo> sp;
    
    // thread 1                      // thread 2    
    bool uniq = sp.unique();    /**/
                                /**/   std::shared_ptr<Foo> cpy = sp;
    if (uniq) {                 /**/
       /* mine?? */             /**/   cpy->foo();
       /* nope :-( */           /**/
    }                           /**/
    

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      相关资源
      最近更新 更多