卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与语法

  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

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

# C++11中的智能指针线程安全性

面试时没有回答好问题是很正常的,被面试官质疑时,要有今天不会明天会的底气,面后做好复盘,不在同一道题目上跌倒第二次,今天就从 C++11中的智能指针线程安全性 背起来

# 简要回答

C++11智能指针的线程安全性遵循"控制块线程安全,对象访问需外部同步"的原则。

shared_ptr的控制块引用计数使用原子操作保证线程安全,但指向的对象的访问需要用户自己保证线程安全。

# 详细回答

C++11智能指针的线程安全性分为几个层面:

控制块安全性:shared_ptr的控制块(包含引用计数、弱计数等)使用原子操作,保证多线程环境下引用计数的正确性。

指针本身操作:对同一个shared_ptr实例的写操作需要同步,读操作可以并发。

指向对象安全性:智能指针不保证其管理对象的线程安全,用户需要自行同步。

不同类型智能指针:

  • shared_ptr:控制块线程安全,实例操作需同步

  • unique_ptr:移动操作非线程安全

  • weak_ptr:与shared_ptr类似,控制块线程安全

# 代码示例

#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include <mutex>

class Data {
public:
    int value = 0;
    void process() {
        // 非线程安全操作
        ++value;
    }
};

std::mutex data_mutex;

// 线程安全的shared_ptr操作
void safe_operation(std::shared_ptr<Data> sp) {
    // 多个线程可以同时拥有指向同一对象的shared_ptr副本
    auto local_sp = sp; // 安全的引用计数操作

    {
        std::lock_guard<std::mutex> lock(data_mutex);
        local_sp->process(); // 需要锁保护实际对象
        std::cout << "Value: " << local_sp->value
                  << " in thread " << std::this_thread::get_id() << std::endl;
    }
}

// 不安全的操作示例
void unsafe_operation(std::shared_ptr<Data>& sp_ref) {
    // 对同一个shared_ptr实例的非const引用操作需要同步
    // 这里存在数据竞争!
    sp_ref->process();
}

int main() {
    auto shared_data = std::make_shared<Data>();

    std::vector<std::thread> threads;

    std::cout << "=== 安全操作示例 ===" << std::endl;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(safe_operation, shared_data);
    }

    for (auto& t : threads) {
        t.join();
    }
    threads.clear();

    std::cout << "最终值: " << shared_data->value << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 知识拓展

  • 知识图解

image

  • 适用场景

shared_ptr引用计数安全:

适用于 共享只读对象 或 写入时复制 的场景。

多个线程可以持有指向同一对象的 shared_ptr,对象的析构会正确延迟到最后一个 shared_ptr离开作用域。

需要同步的场景:

发布-订阅模式:一个线程创建对象并通过 shared_ptr发布给多个工作线程。

发布操作(如写入一个全局 shared_ptr)和订阅操作(读取这个全局 shared_ptr)需要同步(例如使用 std::atomicstd::shared_ptr或锁)。

动态重配置:运行时需要将指向某个资源的 shared_ptr整体替换为指向一个新资源,这个替换操作需要同步。

  • 面试官可能追问

Q1: shared_ptr的引用计数是如何保证线程安全的?

A1: 通过原子操作实现。控制块中的引用计数使用std::atomic类型,所有的增减操作都是原子的,使用适当的内存序(通常是memory_order_relaxed)来保证多线程环境下的正确性。

Q2: 为什么对同一个shared_ptr实例的写操作需要同步?

A2: 因为shared_ptr的写操作(如reset、赋值)涉及多个步骤:修改内部指针、调整引用计数等。如果没有同步,多个线程同时修改会导致数据竞争和未定义行为。

Q3: 如何安全地在多线程环境中传递shared_ptr?

A3: 有几种安全方式:

值传递:函数参数按值传递,自动增加引用计数

const引用 + 内部复制:避免不必要的引用计数操作

使用atomic_shared_ptr(C++20):提供原子操作接口

Q4: 什么是ABA问题?shared_ptr如何避免?

A4: ABA问题是指一个值从A变成B又变回A,但检测不到中间变化。shared_ptr通过组合使用指针值和控制块地址来避免:即使指针值相同,如果控制块不同(对象被销毁后重新创建),也被视为不同的对象。

Last Updated: 3/10/2026, 6:08:48 PM

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

评论

验证登录状态...

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