卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • 关于本专栏
    • C++学习路线
    • C++面试题系优化
  • 基础与语法

  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

    • 什么是智能指针,C++中有哪几种智能指针
    • 智能指针的实现原理是什么?
    • C++11中的智能指针线程安全性
      • 简要回答
      • 详细回答
      • 知识拓展
  • 并发与 I/O

# 智能指针的线程安全性

面试官问"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> 是给真正需要跨线程共享同一个指针变量的场景准备的,按需使用。

Last Updated: 5/23/2026, 4:51:07 PM

← 智能指针的实现原理是什么? 互斥锁与自旋锁 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪