std::shared_ptr 线程安全解释

新手上路,请多包涵

我正在阅读 http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html 并且一些线程安全问题对我来说仍然不清楚:

  1. 标准保证引用计数是线程安全的并且它是独立于平台的,对吗?
  2. 类似的问题 - 标准保证只有一个线程(持有最后一个引用)会在共享对象上调用 delete,对吗?
  3. shared_ptr 不保证存储在其中的对象的任何线程安全?

编辑:

伪代码:

 // Thread I
shared_ptr<A> a (new A (1));

// Thread II
shared_ptr<A> b (a);

// Thread III
shared_ptr<A> c (a);

// Thread IV
shared_ptr<A> d (a);

d.reset (new A (10));

在线程 IV 中调用 reset() 将删除在第一个线程中创建的 A 类的先前实例并用新实例替换它?此外,在 IV 线程中调用 reset() 后,其他线程只会看到新创建的对象吗?

原文由 Goofy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

正如其他人所指出的那样,您已经正确地了解了您最初的 3 个问题。

但是你编辑的结尾部分

在线程 IV 中调用 reset() 将删除在第一个线程中创建的 A 类的先前实例并用新实例替换它?此外,在 IV 线程中调用 reset() 后,其他线程只会看到新创建的对象吗?

是不正确的。 Only d will point to the new A(10) , and a , b , and c will continue to point到原来的 A(1) 。在下面的简短示例中可以清楚地看到这一点。

 #include <memory>
#include <iostream>
using namespace std;

struct A
{
  int a;
  A(int a) : a(a) {}
};

int main(int argc, char **argv)
{
  shared_ptr<A> a(new A(1));
  shared_ptr<A> b(a), c(a), d(a);

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;

  d.reset(new A(10));

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;

  return 0;
}

(显然,我没有打扰任何线程:这不会影响 shared_ptr::reset() 行为。)

这段代码的输出是

a:1 b:1 c:1 d:1

a:1 b:1 c:1 d:10

原文由 Nicu Stiurca 发布,翻译遵循 CC BY-SA 4.0 许可协议

  1. 正确, shared_ptr 使用引用计数值的原子增量/减量。

  2. 该标准保证只有一个线程会调用共享对象上的删除操作符。我不确定它是否明确指定删除其共享指针副本的最后一个线程将是调用 delete 的线程(实际上可能是这种情况)。

  3. 不,他们没有,存储在其中的对象可以由多个线程同时编辑。

编辑:稍微跟进,如果您想了解共享指针的一般工作方式,您可能需要查看 boost::shared_ptr 来源: https ://www.boost.org/doc/libs/release /boost/smart_ptr/shared_ptr.hpp

原文由 NothingMore 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题