std :: shared_ptr线程安全

我读过了

即使对象是共享所有权的副本,多个线程也可以同时读写不同的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?

== ==编辑
只是为了解释我的动机。 我想有一个共享的指针来保存我的configuration,我有一个线程池来处理请求。
所以global是全球configuration。
thread 1正在采取当前configuration,因为它开始处理请求。
thread 2正在更新configuration。 (只适用于未来的请求)

如果工作的话,我可以在不中断请求处理的情况下更新configuration。

你正在阅读的内容并不意味着你的想法。 首先,尝试使用shared_ptr本身的msdn页面。

向下滚动到“备注”部分,你会发现问题的关键。 基本上, shared_ptr<>指向一个“控制块”,它是如何跟踪有多lessshared_ptr<>对象实际上指向“Real”对象。 所以当你这样做的时候:

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

虽然只有1个调用通过make_shared分配内存,但是有两个“逻辑”块不应该这样处理。 一个是存储实际值的int ,另一个是存储所有shared_ptr<> “magic”的控制块。

它只是线程安全的控制块本身。

我把它放在自己的路线上来强调。 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<>实例可以根据需要在不同的线程上创build和销毁。

 //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<>实例的线程安全性仅适用于pipe理相互初始化的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<>是确保多个对象所有者确保对象被破坏的机制,而不是确保多个线程可以正确访问对象的机制。 你仍然需要一个单独的同步机制来安全地在multithreading中使用它(比如std :: mutex )。

最好的方式来考虑它IMO是shared_ptr<>确保指向同一内存的多个副本本身没有同步问题,但对指向的对象不做任何事情。 像这样对待它。

为了增加Kevin所写的内容,C ++ 14规范支持对shared_ptr对象的primefaces访问:

20.8.2.6 shared_ptrprimefaces访问[util.smartptr.shared.atomic]

如果仅通过本节中的函数完成访问,并且将实例作为第一个parameter passing,那么从多个线程并发访问shared_ptr对象不会引入数据争用。

所以如果你这样做:

 //In thread 1 shared_ptr<myClass> private = atomic_load(&global); ... //In thread 2 atomic_store(&global, make_shared<myClass>()); ... 

它将是线程安全的。

这意味着你将有一个有效的shared_ptr和有效的引用计数。

您正在描述尝试读取/分配给相同variables的2个线程之间的争用条件。

因为这是一般的未定义的行为(它只在个别程序的上下文和时间上有意义),shared_ptr不处理。

读操作本身不受数据竞争的影响,因此只要所有线程使用const方法 (包括创build它的副本),共享线程之间的shared_ptr的同一个实例是安全的。 只要一个线程使用非const方法(如在“指向另一个对象”中),这种使用就不再是线程安全的。

OP示例不是线程安全的,并且需要使用线程1中的primefaces负载以及线程2(C ++ 11中的2.7.2.5部分)中的primefaces存储以使线程安全。

MSDN文本中的关键词确实是不同的shared_ptr对象 ,如前面的答案中所述。