std::shared_ptr的引用计数线程安全,但多线程读写同一实例需同步;std::unique_ptr不支持共享,跨线程需转移所有权;std::weak_ptr的lock()线程安全,配合shared_ptr使用可避免循环引用;建议用锁或std::atomic保护指针变量操作,避免竞态。

在多线程环境下使用C++智能指针时,线程安全问题需要特别注意。智能指针本身的行为是否线程安全,取决于具体类型以及使用方式。下面从常见智能指针(std::shared_ptr、std::unique_ptr、std::weak_ptr)的角度分析其在多线程中的安全性,并给出使用建议。
std::shared_ptr 的线程安全特性
std::shared_ptr 的线程安全规则有以下几点:
- 多个线程可以同时读取同一个 shared_ptr 对象(即只读操作是安全的)。
- 多个线程同时修改同一个 shared_ptr 对象(例如赋值、重置)是不安全的,需要外部同步(如互斥锁)。
- 多个 shared_ptr 实例指向同一个对象时,引用计数的增减是原子操作,因此引用计数本身是线程安全的。
也就是说,引用计数安全,但对象访问和指针本身的操作不自动安全。例如:
// 错误:多个线程同时修改同一个 shared_ptr 变量std::shared_ptr
void thread_func() {
ptr = std::make_shared
}
正确做法是使用互斥锁保护对 shared_ptr 变量的写操作:
立即学习“C++免费学习笔记(深入)”;
std::shared_ptr
std::mutex mtx;
void thread_func() {
std::lock_guard<:mutex> lock(mtx);
ptr = std::make_shared
}
std::unique_ptr 的线程安全注意事项
std::unique_ptr 不支持拷贝,通常独占资源。在多线程中使用时注意:
手拉手团购系统是一套Groupon模式的开源团购程序,是骏商网络(dream3.cn)旗下开发的一套仿拉手网团购程序,是国内首套采用ASP+MSSQL开发的团购程序,安装超简,功能超全面,在保留手拉手团购系统版权的前提下,允许所有用户永久免费使用、永久免费升级。手拉手团购系统内置多种主流在线支付接口,所有网银用户均可无障碍支付;短信发送团购券和实物团购快递发货等。 SLStuan手拉手团购程序 v
- 不能在多个线程间共享 unique_ptr 本身(除非转移所有权)。
- 如果一个线程拥有 unique_ptr,其他线程不应访问它,除非通过安全机制转移或释放。
- 跨线程传递 unique_ptr 时,应通过值传递或 std::move,并确保无竞态。
常见做法是用消息队列或条件变量配合 unique_ptr 实现资源传递,避免共享访问。
std::weak_ptr 配合 shared_ptr 使用
std::weak_ptr 通常用于打破 shared_ptr 的循环引用,在多线程中常与 shared_ptr 配合使用。
- weak_ptr 的构造和复制是线程安全的(不影响引用计数)。
- 调用 lock() 获取 shared_ptr 时是线程安全的,因为引用计数增加是原子操作。
- 但多个线程同时调用同一个 weak_ptr 的 lock() 仍建议避免竞态,尤其是 weak_ptr 本身被修改时。
示例:
std::shared_ptr
std::weak_ptr
void observer() {
auto p = weak.lock(); // 安全:原子增加引用计数
if (p) {
p->do_something(); // 操作的是副本,安全
}
}
实际使用建议
在多线程环境中使用智能指针,遵循以下原则可避免问题:
- 不要在多个线程中直接读写同一个智能指针变量,尤其是 shared_ptr 的赋值。
- 若需共享对象,优先使用 std::shared_ptr,并通过锁保护指针变量本身的操作。
- 避免长时间持有 shared_ptr 而频繁访问目标对象,对象本身的线程安全需另行保证。
- 使用 std::make_shared 替代 new + shared_ptr 构造,提高性能和异常安全。
- 考虑使用 std::atomic<:shared_ptr>>(C++20 起支持)进行无锁的 shared_ptr 赋值和读取。
基本上就这些。智能指针的引用计数机制是线程安全的,但指针变量的操作不是。只要注意同步 shared_ptr 变量的修改,合理使用 weak_ptr 观察对象生命周期,就能在多线程中安全使用。不复杂但容易忽略。









