C++11:如何在std::thread执行函数退出后立即调用join()?
咱们先看你给出的代码实现:
class MyClass { private: std::thread auxThread; void run(); public: ~MyClass(); void start(); }; MyClass::~MyClass() { if (auxThread.joinable()) auxThread.join(); } void MyClass::run() { //do stuff } void MyClass::start() { auxThread = std::thread (&MyClass::run, this); //Move assignment }
接下来针对你的两个问题逐一解答:
问题1:如果从不join已经退出的线程,会消耗系统资源吗?
当run()执行完毕,线程的用户态逻辑确实结束了,但内核层面的线程资源(比如线程控制块、栈空间等)不会自动释放——这些资源会被操作系统保留,直到你主动调用join()来回收,或者调用detach()告知系统“线程结束后自行清理资源”。
哪怕线程已经执行完,只要你没调用join或detach,std::thread对象就会一直处于*joinable()状态。这时候调用join()会立即返回,但必须调用它才能释放那些残留的内核资源;如果一直不处理,这些资源会持续被占用,属于隐性的资源泄漏。另外,如果不小心销毁了处于joinable()*状态的std::thread对象(比如没在析构里做处理),程序会直接触发std::terminate()崩溃,这也是你当前析构函数加判断的原因。
总结一下:线程执行完后不join会持续占用内核资源,必须通过join或detach完成资源释放。
问题2:能不能让主线程响应run()的退出,调用join()但不阻塞主线程?
当然可以,这里给你几个实用的实现方案:
方案1:原子标记+主线程空闲轮询
在MyClass里新增一个原子布尔变量,用来标记线程是否完成:
#include <atomic> class MyClass { private: std::thread auxThread; std::atomic<bool> thread_finished{false}; // 新增标记 void run(); public: ~MyClass(); void start(); // 主线程可以在循环里调用这个函数 void try_join(); };
然后在run()的最后一行设置标记:
void MyClass::run() { // do your stuff thread_finished = true; }
主线程在自己的业务循环(比如事件循环、主逻辑循环)里,每次循环都调用try_join()做轻量检查:
void MyClass::try_join() { if (thread_finished && auxThread.joinable()) { auxThread.join(); thread_finished = false; // 重置标记,避免重复处理 } }
这种方式完全不会阻塞主线程,只是在每次循环里做个无开销的原子检查,一旦发现线程结束就立即回收资源。
方案2:后台监控线程
在start()创建工作线程的同时,再创建一个专门的监控线程,它的唯一任务就是等待工作线程结束并调用join():
void MyClass::start() { auxThread = std::thread(&MyClass::run, this); // 创建监控线程,注意要保证MyClass对象生命周期长于工作线程 std::thread monitor([this]() { if (auxThread.joinable()) { auxThread.join(); // 这里还可以加线程结束后的回调逻辑,比如通知主线程做后续处理 } }); monitor.detach(); // 让监控线程后台运行,自行结束 }
这个监控线程会在后台默默等待工作线程结束,自动完成join操作,完全不会干扰主线程的正常运行。
方案3:用std::packaged_task + std::future实现非阻塞检查
把run()包装成std::packaged_task,通过std::future来非阻塞地判断线程是否结束:
#include <future> class MyClass { private: std::thread auxThread; std::future<void> thread_future; // 新增future成员 void run(); public: ~MyClass(); void start(); void check_and_join(); }; void MyClass::start() { std::packaged_task<void()> task(std::bind(&MyClass::run, this)); thread_future = task.get_future(); auxThread = std::thread(std::move(task)); } void MyClass::check_and_join() { // 非阻塞检查future是否就绪(即线程是否执行完毕) if (thread_future.valid() && thread_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { thread_future.get(); // 这里等价于join,获取任务结果 if (auxThread.joinable()) { auxThread.join(); } } }
主线程可以在合适的时机(比如事件间隙)调用check_and_join(),这个调用是立即返回的,只有当线程已经结束时才会执行join操作,完全不会阻塞主线程。
内容的提问来源于stack exchange,提问作者CCJ

