gpt4 book ai didi

c++ - std::shared_ptr 线程安全

转载 作者:太空宇宙 更新时间:2023-11-04 12:56:13 26 4
gpt4 key购买 nike

我读过

"Multiple threads can simultaneously read and write different shared_ptr objects, even when the objects are copies that share ownership." (MSDN: Thread Safety in the Standard C++ Library)

这是否意味着更改 shared_ptr 对象是安全的?
例如,下一个代码是否被认为是安全的:

shared_ptr<myClass> global = make_shared<myClass>();
...

//In thread 1
shared_ptr<myClass> private = global;
...

//In thread 2
global = make_shared<myClass>();
...

在那种情况下,我能否确定线程 1 private 将具有 global 的原始值或线程 2 分配的新值,但无论哪种方式,它都会有一个myClass 的有效 shared_ptr?

==编辑==
只是为了解释我的动机。我想要一个共享指针来保存我的配置,并且我有一个线程池来处理请求。
所以global是全局配置。
线程 1 在开始处理请求时采用当前配置。
线程 2 正在更新配置。 (仅适用于 future 的请求)

如果可行,我可以通过这种方式更新配置,而不会在请求处理过程中中断它。

最佳答案

您正在阅读的内容并不代表您认为的意思。首先,尝试 shared_ptr 的 msdn 页面本身。

向下滚动到“备注”部分,您将了解问题的实质。基本上,一个 shared_ptr<>指向一个“控制 block ”,这是它如何跟踪有多少shared_ptr<>对象实际上指向“真实”对象。所以当你这样做时:

shared_ptr<int> ptr1 = make_shared<int>();

虽然这里只有 1 次调用通过 make_shared 分配内存,有两个“逻辑” block 你不应该对待相同。一个是 int其中存储实际值,另一个是控制 block ,存储所有shared_ptr<>让它发挥作用的“魔法”。

只有控制 block 本身是线程安全的。

为了强调,我把它单独放在一行。 shared_ptr内容不是线程安全的,也不是写入相同的 shared_ptr实例。这里有一些东西可以证明我的意思:

// In main()
shared_ptr<myClass> global_instance = make_shared<myClass>();
// (launch all other threads AFTER global_instance is fully constructed)

//In thread 1
shared_ptr<myClass> local_instance = global_instance;

这很好,事实上您可以在所有线程中尽可能多地执行此操作。然后当local_instance被破坏(通过超出范围),它也是线程安全的。有人可以访问 global_instance这不会有什么不同。您从 msdn 中提取的代码段基本上意味着“对控制 block 的访问是线程安全的”,所以其他 shared_ptr<>可以根据需要在不同的线程上创建和销毁实例。

//In thread 1
local_instance = make_shared<myClass>();

这很好。它影响global_instance对象,但只是间接的。它指向的控制 block 将递减,但以线程安全的方式完成。 local_instance将不再指向与 global_instance 相同的对象(或控制 block )

//In thread 2
global_instance = make_shared<myClass>();

如果global_instance,这几乎肯定是不好的从任何其他线程访问(你说你正在做)。如果你这样做,它需要一个锁,因为你正在写任何地方 global_instance生活,而不仅仅是阅读它。所以从多个线程写入一个对象是不好的,除非你通过锁来保护它。所以你可以阅读 global_instance通过分配新的对象 shared_ptr<>来自它的对象,但你不能写入它。

// In thread 3
*global_instance = 3;
int a = *global_instance;

// In thread 4
*global_instance = 7;

a 的值未定义。它可能是 7,也可能是 3,也可能是其他任何值。 shared_ptr<> 的线程安全实例仅适用于管理 shared_ptr<>从彼此初始化的实例,而不是它们指向的实例。

为了强调我的意思,请看这个:

shared_ptr<int> global_instance = make_shared<int>(0);

void thread_fcn();

int main(int argc, char** argv)
{
thread thread1(thread_fcn);
thread thread2(thread_fcn);
...
thread thread10(thread_fcn);

chrono::milliseconds duration(10000);
this_thread::sleep_for(duration);

return;
}

void thread_fcn()
{
// This is thread-safe and will work fine, though it's useless. Many
// short-lived pointers will be created and destroyed.
for(int i = 0; i < 10000; i++)
{
shared_ptr<int> temp = global_instance;
}

// This is not thread-safe. While all the threads are the same, the
// "final" value of this is almost certainly NOT going to be
// number_of_threads*10000 = 100,000. It'll be something else.
for(int i = 0; i < 10000; i++)
{
*global_instance = *global_instance + 1;
}
}

A shared_ptr<>是一种确保多个对象所有者确保对象被销毁的机制,而不是确保多个线程可以正确访问对象的机制。您仍然需要一个单独的同步机制才能在多个线程中安全地使用它(例如 std::mutex )。

考虑 IMO 的最佳方式是 shared_ptr<>确保指向同一内存的多个拷贝对自身没有同步问题,但对指向的对象不做任何事情。那样对待它。

关于c++ - std::shared_ptr 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46547668/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com