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

如何从deleter重置自引用unique_ptr并避免Watcher线程空指针解引用

问题分析与修复方案

问题根源

你提到的在重置unique_ptr前先停止Watcher线程是完全可行的,也是解决这个空指针问题的正确方案,现有代码触发错误的核心原因有2个:

  • 析构时序存在竞态:Main默认析构函数会直接析构watcher成员,在Watcher析构函数执行到stop = true之前,子线程仍可能调用main.event(),此时watcher已经处于析构流程中,访问watcher->eventInfo()属于未定义行为。
  • 线程同步缺失:stop是普通bool类型,多线程下的读写没有同步保障,子线程可能感知不到stop状态的更新,导致线程持续运行。

修复代码

#include <iostream>
#include <memory>
#include <thread>
#include <atomic>

struct Main {
    struct Watcher {
        Watcher(Main &main)
            : main(main)
            , th(std::thread(&Watcher::func, this))
        { }
        
        void func() { 
            while (!stop.load(std::memory_order_acquire)) {
                main.event(); 
            }
        }        
        
        int eventInfo() { return 0; }

        // 新增主动停止接口
        void stop() {
            stop.store(true, std::memory_order_release);
            if (th.joinable()) {
                th.join();
            }
        }
        
        ~Watcher()
        {
            // 析构时兜底停止,避免外部忘记调用
            stop();
        }
        
        Main &main;
        std::thread th;
        std::atomic<bool> stop{}; // 改为原子类型保证线程可见性
    };

    Main()
        : watcher(std::make_unique<Watcher>(*this))
    { }

    // 自定义析构函数,控制停止时序
    ~Main() {
        if (watcher) {
            // 先停止线程,确保子线程不再调用event
            watcher->stop();
            // 线程完全停止后再释放Watcher对象
            watcher.reset();
        }
    }

    void event() { 
        // 这里可以保留判空做双重保险,正常时序下不会走到空分支
        if (watcher) {
            std::cout << watcher->eventInfo() << "\n"; 
        }
    }
    
    std::unique_ptr<Watcher> watcher;
};

修复逻辑说明

  • 主动控制析构时序:Main析构时先调用watcher->stop()等待子线程完全退出,保证后续不会再有event回调触发,再释放Watcher对象,从根源上避免访问处于析构状态的watcher。
  • 线程安全保障:将stop改为std::atomic<bool>,搭配内存序保证多线程下状态更新的可见性,避免数据竞争。
  • 双重兜底:Watcher析构函数仍保留停止逻辑,避免外部场景下忘记主动调用stop()导致的资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 10:24:03