Roe*_*rel 43 c++ 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>();
...
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我可以确定线程1 private将具有global线程2分配的原始值或新值,但无论哪种方式,它将具有对myClass的有效shared_ptr?
==编辑==
只是为了解释我的动机.我想有一个共享指针来保存我的配置,我有一个线程池来处理请求.全局配置也是
如此global.
thread 1在开始处理请求时采用当前配置.
thread 2正在更新配置.(仅适用于未来的请求)
如果它工作,我可以更新配置,而不会在请求处理过程中中断它.
Kev*_*son 87
你所读到的并不意味着你认为它意味着什么.首先,尝试使用shared_ptr本身的msdn页面.
向下滚动到"备注"部分,您将了解问题的主要内容.基本上,shared_ptr<>指向"控制块",它是如何跟踪shared_ptr<>实际指向"真实"对象的对象的数量.所以当你这样做时:
shared_ptr<int> ptr1 = make_shared<int>();
Run Code Online (Sandbox Code Playgroud)
虽然这里只有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;
Run Code Online (Sandbox Code Playgroud)
这很好,事实上你可以在所有线程中尽可能多地执行此操作.然后当local_instance被破坏时(超出范围),它也是线程安全的.有人可以访问global_instance,它不会有所作为.从msdn中提取的片段基本上意味着"访问控制块是线程安全的",因此shared_ptr<>可以根据需要在不同的线程上创建和销毁其他实例.
//In thread 1
local_instance = make_shared<myClass>();
Run Code Online (Sandbox Code Playgroud)
这可以.它会影响global_instance对象,但只是间接影响.它指向的控制块将递减,但以线程安全的方式完成. local_instance将不再指向同一个对象(或控制块)global_instance.
//In thread 2
global_instance = make_shared<myClass>();
Run Code Online (Sandbox Code Playgroud)
如果global_instance从任何其他线程(您说你正在做)访问,这几乎肯定是不好的.如果你这样做,它需要锁定,因为你写的是global_instance生活的任何地方,而不仅仅是从中读取.因此,从多个线程写入对象是不好的,除非你通过锁保护它.因此,您可以global_instance通过从对象中分配新shared_ptr<>对象来读取对象,但您无法写入该对象.
// In thread 3
*global_instance = 3;
int a = *global_instance;
// In thread 4
*global_instance = 7;
Run Code Online (Sandbox Code Playgroud)
值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;
}
}
Run Code Online (Sandbox Code Playgroud)
A shared_ptr<>是一种确保多个对象所有者确保对象被破坏的机制,而不是确保多个线程可以正确访问对象的机制.您仍然需要一个单独的同步机制来在多个线程中安全地使用它(比如std :: mutex).
考虑它的最佳方式IMO是shared_ptr<>确保指向同一内存的多个副本本身没有同步问题,但不会对指向的对象执行任何操作.像那样对待它.
Chr*_*odd 24
为了补充Kevin写的内容,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>());
...
Run Code Online (Sandbox Code Playgroud)
它将是线程安全的.
这意味着您将拥有有效的shared_ptr和 有效的引用计数。
您正在描述试图读取/分配给同一变量的两个线程之间的竞争条件。
因为这通常是未定义的行为(它仅在单个程序的上下文和时间中有意义),因此shared_ptr无法处理该问题。