线程销毁自身所属对象时调用thread.detach()的技术问题咨询
咱们来拆解一下你这段代码里的问题——这其实是个典型的线程生命周期和对象生命周期冲突的坑,你的实现存在严重的未定义行为,具体问题如下:
线程操作自身关联的线程对象:当
run()里调用classB->endThisObject(this)时,本质是在当前运行的myThread线程里执行delete this,触发myClass的析构函数。而析构里调用的myThread.detach(),是让当前线程尝试分离自己。但此时myThread作为myClass的成员,所在的对象内存已经开始被回收,操作这个正在销毁的线程对象,会直接触发未定义行为——C++标准不允许在对象析构过程中,由对象自身的线程操作该线程成员。对象销毁后线程仍在执行上下文:就算
detach()侥幸执行成功,当前线程在run()函数里,执行完delete this之后,还要从run()函数返回。但此时this指针已经是野指针,run()作为myClass的成员函数,其执行依赖的对象上下文已经被销毁,后续的函数返回操作会访问已释放的内存,同样是未定义行为。析构顺序的隐性风险:
myClass的成员销毁顺序是声明顺序的逆序——myThread先声明,classB后声明,所以析构时会先销毁classB指针(只是销毁指针本身,不是指向的ClassB对象),再销毁myThread。但你在析构里主动调用myThread.detach()时,myThread还没被销毁,但此时对象整体已经进入析构流程,线程操作自身所属对象的成员,本身就是不安全的。
怎么调整才安全?
核心原则是:绝对不要让线程自身触发所属对象的销毁,应该把对象生命周期的管理交给外部,确保销毁对象时线程已经完全停止。这里给你一个简单的改进思路:
#include <memory> #include <thread> class ClassB; class myClass : public std::enable_shared_from_this<myClass> { public: myClass(std::shared_ptr<ClassB> x) : classB(std::move(x)) { myThread = std::thread(&myClass::run, this); } ~myClass() { if (myThread.joinable()) { myThread.join(); // 确保线程完全结束后再销毁对象 } } void run() { while (something) { // 执行你的业务逻辑 } // 只通知ClassB线程已完成,不直接销毁自己 classB->notifyThreadComplete(shared_from_this()); } private: std::thread myThread; std::shared_ptr<ClassB> classB; }; class ClassB { public: void notifyThreadComplete(std::shared_ptr<myClass> x) { // 这里可以做一些收尾操作,x会在离开作用域时自动销毁 // 此时myClass的析构函数会确保线程已经join完成 } };
这个调整用std::shared_ptr管理myClass的生命周期,线程结束后只通知ClassB,由智能指针自动处理对象销毁,确保销毁时线程已经完全停止,从根源上避免了生命周期冲突的问题。
内容的提问来源于stack exchange,提问作者Druudik

