shared_ptr引用计数线程安全,但多线程读写同一shared_ptr变量需用std::atomic<shared_ptr<T>>;unique_ptr不可共享,跨线程传递需std::move并确保所有权清晰;智能指针不保证所指对象的线程安全,访问共享对象仍需同步机制。
智能指针在多线程环境下使用时,线程安全问题必须谨慎处理。c++标准库中的智能指针各有不同的线程安全特性,理解这些特性并结合原子操作,是保障并发安全的关键。
shared_ptr 的线程安全机制
shared_ptr 的引用计数是线程安全的,这意味着多个线程同时增加或减少引用计数不会导致数据竞争。标准要求对引用计数的修改是原子的。
但注意:多个线程读写同一个 shared_ptr 对象(即指向同一块控制块的多个副本)时,如果涉及赋值或重置,仍需外部同步。
常见场景:
- 线程A和线程B各自持有同一个 shared_ptr 的副本,各自析构时引用计数自动减一,安全。
- 线程A和线程B同时对同一个 shared_ptr 变量进行赋值(如 sp = new_ptr),则必须加锁或使用原子操作。
使用 atomic_shared_ptr 保障操作原子性
C++11起,可以通过 std::atomic_load 和 std::atomic_store 等函数对 shared_ptr 进行原子读写。但从 C++20 开始,推荐使用 std::atomic<std::shared_ptr<T>>,它提供了更直观的接口。
立即学习“C++免费学习笔记(深入)”;
例如:
std::atomic<std::shared_ptr<Data>> global_data; // 线程中安全更新 auto new_data = std::make_shared<Data>(); global_data.store(new_data); // 安全读取 auto current = global_data.load();
这样可以避免多个线程同时修改同一个 shared_ptr 变量导致的竞争。
unique_ptr 的线程安全特点
unique_ptr 不支持共享,本身不可复制,通常只在一个线程中持有。因此,它不涉及引用计数,也没有内置的线程安全机制。
如果需要跨线程转移所有权,应使用 std::move,并在转移时确保没有其他线程正在访问该指针。典型做法是配合互斥锁或通过消息队列传递 unique_ptr。
避免常见陷阱
即使引用计数安全,也不能忽视对所指向对象的访问安全。多个 shared_ptr 共享同一个对象时,对象本身的读写仍需同步机制保护。
关键点总结:
- shared_ptr 的引用计数线程安全,操作 shared_ptr 变量本身不一定安全。
- 多线程读写同一 shared_ptr 变量时,使用 std::atomic<shared_ptr<T>>。
- unique_ptr 应避免共享,跨线程传递需确保所有权清晰。
- 智能指针安全不等于所指对象安全,对象访问仍需加锁或其它同步手段。
基本上就这些。合理使用原子智能指针和同步机制,能有效避免资源泄漏和竞态条件。