std::shared_ptr 在多大程度上确保线程安全?

发布于 2025-01-02 12:16:34 字数 719 浏览 3 评论 0 原文

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

  1. 标准保证引用计数的处理是线程安全的并且它是独立于平台的,对吗?
  2. 类似的问题 - 标准保证只有一个线程(保存最后一个引用)会调用共享对象上的删除,对吧?
  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() 后,其他线程只会看到新创建的对象?

I'm reading http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html and some thread safety issues are still not clear for me:

  1. Standard guarantees that reference counting is handled thread safe and it's platform independent, right?
  2. Similar issue - standard guarantees that only one thread (holding last reference) will call delete on shared object, right?
  3. shared_ptr does not guarantee any thread safety for object stored in it?

EDIT:

Pseudo code:

// 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));

Calling reset() in thread IV will delete previous instance of A class created in first thread and replace it with new instance? Moreover after calling reset() in IV thread other threads will see only newly created object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萤火眠眠 2025-01-09 12:16:34

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

但你编辑的结尾部分

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

是不正确的。只有 d 会指向新的 A(10),以及 abc 将继续指向原来的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

As others have pointed out, you've got it figured out correctly regarding your original 3 questions.

But the ending part of your edit

Calling reset() in thread IV will delete previous instance of A class created in first thread and replace it with new instance? Moreover after calling reset() in IV thread other threads will see only newly created object?

is incorrect. Only d will point to the new A(10), and a, b, and c will continue to point to the original A(1). This can be seen clearly in the following short example.

#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;                                                                                                          
}

(Clearly, I didn't bother with any threading: that doesn't factor into the shared_ptr::reset() behavior.)

The output of this code is

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

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

孤寂小茶 2025-01-09 12:16:34
  1. 正确,shared_ptr使用引用计数值的原子增量/减量。

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

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

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

  1. Correct, shared_ptrs use atomic increments/decrements of a reference count value.

  2. The standard guarantees only one thread will call the delete operator on a shared object. I am not sure if it specifically specifies the last thread that deletes its copy of the shared pointer will be the one that calls delete (likely in practice this would be the case).

  3. No they do not, the object stored in it can be simultaneously edited by multiple threads.

EDIT: Slight followup, if you want to get an idea of how shared pointers work in general you might want to look at the boost::shared_ptr source: https://www.boost.org/doc/libs/release/boost/smart_ptr/shared_ptr.hpp.

回眸一笑 2025-01-09 12:16:34

std::shared_ptr 不是线程安全的。

共享指针是一对两个指针,一个指向对象,一个指向控制块(保存引用计数器,链接到弱指针......)。

可以有多个 std::shared_ptr ,每当它们访问控制块以更改引用计数器时,它都是线程安全的,但 std::shared_ptr 本身不是线程安全的或原子的。

如果您将一个新对象分配给 std::shared_ptr 而另一个线程使用它,则它最终可能会得到新对象指针,但仍然使用指向旧对象控制块的指针 =>碰撞。

std::shared_ptr is not thread safe.

A shared pointer is a pair of two pointers, one to the object and one to a control block (holding the ref counter, links to weak pointers ...).

There can be multiple std::shared_ptr and whenever they access the control block to change the reference counter it's thread-safe but the std::shared_ptr itself is NOT thread-safe or atomic.

If you assign a new object to a std::shared_ptr while another thread uses it, it might end up with the new object pointer but still using a pointer to the control block of the old object => CRASH.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文