- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我读过
"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/
我是一名优秀的程序员,十分优秀!