# 智能指针的线程安全性
面试官问"shared_ptr 是线程安全的吗",很多人直接答"是"或者"不是"——两种回答都不准确。这道题考的是你能不能把"哪部分安全、哪部分不安全"说清楚,答不出这个层次就会被追问到底。
# 简要回答
一句话:控制块线程安全,对象访问不安全,指针实例本身的并发写也不安全。shared_ptr 的引用计数加减是原子操作,但它管理的对象和 shared_ptr 变量本身都需要你自己加锁。
# 详细回答
智能指针的线程安全要分三个层面来看:
第一层:控制块(引用计数)— 线程安全
shared_ptr 内部的控制块用 std::atomic 实现引用计数的加减。多个线程同时拷贝、析构各自持有的 shared_ptr 副本,引用计数不会出错。这是标准保证的。
第二层:shared_ptr 实例本身 — 不安全
同一个 shared_ptr 变量,多个线程同时读没问题,但如果有线程在写(reset、赋值、移动),就必须加锁。因为写操作要同时修改内部指针和调整引用计数,不是一个原子步骤。
第三层:管理的对象 — 不安全
智能指针只管生命周期,不管对象内部的并发访问。多个线程通过各自的 shared_ptr 副本访问同一个对象,读写对象的成员仍然需要 mutex 保护。
对于 unique_ptr,它本身就是独占语义,不存在共享的场景。所有权转移(move)不是线程安全的,必须确保同一时刻只有一个线程操作它。

# 知识拓展
Q:引用计数用的什么内存序?
增加计数用 memory_order_relaxed 就够了,因为不需要同步其他数据。但减少计数用 memory_order_acq_rel——减到零时要释放对象,必须保证之前所有线程对对象的写入都对当前线程可见。
Q:怎么安全地在线程间传递 shared_ptr?
最简单的方式是值传递——函数参数按值接收 shared_ptr,拷贝时引用计数原子加一,各线程持有独立副本,互不干扰。如果要修改一个全局的 shared_ptr 变量,C++20 提供了 std::atomic<std::shared_ptr<T>>,之前的版本只能用 mutex。
Q:多线程同时读同一个 shared_ptr 变量安全吗?
安全。标准规定对同一个 shared_ptr 实例的并发只读访问不构成数据竞争。但只要有一个线程在写,所有访问都必须同步。
Q:为什么不把 shared_ptr 整体做成原子的?
性能代价太大。绝大多数场景下 shared_ptr 是线程局部使用的,每次操作都走原子指令会白白浪费性能。C++20 的 atomic<shared_ptr> 是给真正需要跨线程共享同一个指针变量的场景准备的,按需使用。
← 智能指针的实现原理是什么? 互斥锁与自旋锁 →
评论
验证登录状态...