我读过
这是否意味着更改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
是全局配置。thread 1
在开始处理请求时采用当前配置。thread 2
正在更新配置。 (仅适用于将来的请求)如果可行,我可以用这种方式更新配置,而不会在请求处理过程中中断配置。
最佳答案
您正在阅读的内容并不意味着您认为的意思。首先,尝试msdn页面上的shared_ptr本身。
向下滚动到“备注”部分,您将了解问题的实质。基本上,shared_ptr<>
指向“控制块”,这是它跟踪实际上有多少shared_ptr<>
对象指向“Real”对象的方式。因此,当您执行此操作时:
shared_ptr<int> ptr1 = make_shared<int>();
虽然这里只有1个通过
make_shared
分配内存的调用,但是有两个“逻辑”块不应该相同。一个是存储实际值的int
,另一个是控制块,该控制块存储了使它起作用的所有shared_ptr<>
“魔术”。只有控制块本身才是线程安全的。
我强调这一点。
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中提取的代码段基本上意味着“对控制块的访问是线程安全的”,因此可以根据需要在其他线程上创建和销毁其他shared_ptr<>
实例。//In thread 1
local_instance = make_shared<myClass>();
这可以。它会影响
global_instance
对象,但只会间接影响。它指向的控制块将递减,但以线程安全的方式完成。 local_instance
将不再与global_instance
指向相同的对象(或控制块)。//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
的值 undefined 。可能是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;
}
}
shared_ptr<>
是确保多个对象所有者确保对象被破坏的机制,而不是确保多个线程可以正确访问对象的机制。您仍然需要单独的同步机制才能在多个线程中安全地使用它(例如std::mutex)。最好的考虑方式IMO是
shared_ptr<>
确保指向同一内存的多个副本本身没有同步问题,但对所指向的对象不做任何事情。那样对待。关于c++ - std::shared_ptr线程安全,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46547668/