std::shared_ptr 最容易被误解成“用了它对象就线程安全”。它真正提供的是共享所有权:不同 shared_ptr 实例指向同一控制块时,引用计数增减可以安全并发,最后一个所有者释放时对象被销毁。但被管理对象内部字段依然是普通数据;同一个 shared_ptr 变量本身被多个线程同时读写也仍可能发生数据竞争。
三层线程安全要分开看
第一层是控制块:引用计数和弱引用计数由实现以线程安全方式维护。第二层是 shared_ptr 实例:两个独立实例可并发复制/销毁;但一个同名变量被一个线程赋值、另一个线程读取时,需要同步。第三层是对象:shared_ptr<T> 不会给 T 的成员函数加锁,多个线程修改 T 仍须由 T 自己提供 mutex、原子或消息传递策略。
发布共享对象的安全方式
若一个线程创建新配置对象,另一个线程周期性读取,可用 mutex 保护那个共享变量,或在 C++20 支持下使用 std::atomic<std::shared_ptr<T>> 的 load/store。无论哪种,只保证“拿到的是哪一个对象”;对象内部是否可变仍需单独协议。
1 | std::atomic<std::shared_ptr<const Config>> current; |
不可变快照 + 原子替换常比多线程共改一个大对象简单得多。对实时路径而言,也避免了在读配置时持有长 mutex。
循环引用和析构线程同样重要
两个对象互持 shared_ptr 会让强引用永远不为零,应将非拥有或反向链接改为 weak_ptr。此外,最后一个引用的释放可能发生在任意线程,若对象析构会关闭设备、做 I/O 或持锁,就会把不可控工作放进释放路径。可将资源关闭与内存所有权分离,或在受控线程中显式 stop()/join()。
shared_ptr 解决的是所有权共享,不是并发状态管理。把“谁拥有对象”“谁能修改对象”“对象何时停止”三件事分别设计,才不会让原子引用计数掩盖数据竞争。