我读过,
“多线程可以同时读取和写入不同的shared_ptr对象,即使对象是股权份。” ( MSDN:标准C ++库中的线程安全 )
这是否意味着改变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分配的新值,但无论哪种方式,都会有一个有效的shared_ptr来MYCLASS?
== ==编辑
只是为了解释我的动机。 我想有一个共同的指向握住我的配置,我有一个线程池来处理请求。
所以global
的全局配置。
thread 1
走的是当前配置,因为它开始处理请求。
thread 2
被更新配置。 (仅适用于未来的请求)
如果它的工作,我可以更新配置这种方式没有的请求处理中间打破它。
你正在阅读是不是意味着你认为这意味着什么。 首先,尝试在MSDN页面shared_ptr的本身。
向下滚动到“备注”部分,你会得到这个问题的肉。 基本上,一个shared_ptr<>
指向一个“控制块”,这是它如何跟踪的许多如何shared_ptr<>
对象实际上指向“真正的”对象。 所以,当你这样做:
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
是不确定的。 这可能是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<>
是一种机制,以确保多个对象所有者确保一个目的是破坏,不以确保多线程能够正确地访问对象的机制。 你还需要一个单独的同步机制,在多线程安全地使用它(如性病::互斥体 )。
国际海事组织去想它,最好的办法是, shared_ptr<>
可以确保指向相同的存储多个副本没有同步问题本身 ,但不会做任何事情的指向的对象。 把它当作是这样的。
要添加到什么凯文写道,在C ++ 14规范有原子访问shared_ptr的额外支持对象本身:
20.8.2.6 shared_ptr
原子访问[util.smartptr.shared.atomic]
到并发访问shared_ptr
如果访问是专门通过功能在本节进行,该实例作为他们的第一个参数传递从多个线程对象不引入数据争。
所以,如果你这样做:
//In thread 1
shared_ptr<myClass> private = atomic_load(&global);
...
//In thread 2
atomic_store(&global, make_shared<myClass>());
...
这将是线程安全的。
这意味着你将有一个有效shared_ptr
,和一个有效的引用计数。
你所描述的2个线程之间的竞争条件正试图读/分配给同一个变量。
因为这是一般未定义的行为(它才有意义,在个别项目的背景和时机) shared_ptr
不处理。
读操作不受它们之间的数据竞争,因此它是安全的,只要所有线程只使用const的方法线程之间共享shared_ptr的的同一个实例(这包括创建它的副本)。 只要一个线程使用非const方法(如“它指向另一个对象”)这样的使用不再是线程安全的。
的OP示例不是线程安全,并需要(在C ++ 11节2.7.2.5)在线程1和线程在2原子商店使用原子负荷,使其线程安全的。
在MSDN文本的关键词是确实不同shared_ptr对象 ,如以前的答案已经提到。