You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程安全性疑问:并发场景下shared_ptr与计数器访问问题

作为并发编程新手,你的判断完全正确——这段代码确实存在多处线程安全问题,执行结果是未定义的。下面我逐个解答你的疑问:

疑问1:Middle::inner_data中对data_->counter的访问是否安全?

完全不安全,存在两层数据竞争:

  • 第一层是对std::shared_ptr<Inner> data_的访问:Middle的后台线程在频繁调用data_.reset(new Inner)(写操作),而main线程通过inner_data()读取data_指向的对象(读操作),这两个操作没有任何同步机制,属于对同一个shared_ptr实例的并发读写,违反了shared_ptr的线程安全规则。
  • 第二层是对counter_的访问:Inner的后台线程在持续自增counter_(写操作),main线程在读取这个值(读操作),std::uint64_t的读写在部分平台上并非原子操作,而且两者之间没有互斥锁、条件变量或内存屏障,会导致数据撕裂或读取到不一致的值,属于典型的数据竞争,触发未定义行为。
疑问2:线程A持有成员shared_ptr sp并决定更新它,同时线程B执行shared_ptr sp = A::sp,该复制与销毁操作是否线程安全?是否存在因对象正在销毁而导致复制失败的风险?

首先明确shared_ptr的线程安全边界:

  • 多个线程对不同的shared_ptr实例进行任意操作(包括读写)都是安全的;
  • 多个线程对同一个shared_ptr实例的读操作(比如复制构造、赋值、获取引用计数)是安全的;
  • 但如果对同一个shared_ptr实例同时进行写操作(比如reset、赋值新对象)和读/写操作,则完全不安全,属于数据竞争。

回到你的场景:线程A对sp执行reset(写操作),线程B同时复制sp(读操作),这是并发读写同一个shared_ptr实例,属于未定义行为。

关于复制失败的风险:确实存在。虽然shared_ptr的引用计数操作是原子的,但shared_ptr内部的指针和引用计数是两个独立的成员,并发读写时可能出现“指针已经指向被销毁的对象,但引用计数还没来得及更新”的情况,导致线程B复制出的shared_ptr指向一个已经被销毁的对象,后续访问这个对象会触发未定义行为(比如崩溃、读取垃圾值)。

疑问3:在何种情况下,未定义行为可能导致std::terminate?能否通过工具检测此类情况?

可能触发std::terminate的场景

未定义行为的结果是不可预测的,但在你的代码中,以下情况可能导致std::terminate:

  1. 线程异常未捕获:如果Inner或Middle的后台线程在执行过程中抛出未捕获的异常,会直接触发std::terminate;
  2. 析构函数抛出异常:如果Inner的析构函数中join线程时发生异常(比如线程已经被 detach 或处于无效状态),而析构函数本身没有捕获异常,会导致std::terminate;
  3. 非法内存访问导致的崩溃:当main线程访问已经被销毁的Inner对象的counter_时,可能触发段错误,部分操作系统会将这种错误转化为异常,最终导致std::terminate;
  4. double free:如果shared_ptr的并发读写导致引用计数计算错误,可能出现同一个对象被多次释放的情况,触发内存错误,进而导致std::terminate。

检测工具

这类并发问题可以通过以下工具检测:

  • 静态分析工具:Clang-Tidy、Cppcheck,能在编译阶段发现潜在的线程安全问题(比如未同步的共享变量访问);
  • 动态分析工具:
    • ThreadSanitizer(TSAN):专门检测数据竞争,能精准定位到代码中并发读写的位置;
    • Valgrind的Helgrind/DRD:检测线程同步错误和数据竞争;
    • AddressSanitizer(ASAN):检测非法内存访问、double free等内存错误,常和TSAN配合使用。

你的示例程序运行多日未出现异常,只是未定义行为的“幸运”情况——未定义行为不代表一定会崩溃,只是结果不可靠,在生产环境中可能会在极端负载或特定平台下突然爆发问题,必须修复。

内容的提问来源于stack exchange,提问作者arynaq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:17:11