1. 背景
在debug项目代码时,发现程序总是发生挂死问题,提示terminate called without an active exception,根据网上资料,大概定位到是std::thread析构函数引起。有同事大量使用std::thread创建线程,例如:
m_thread = std::thread([this]() {
this->run();
});
而挂死原因正是因为这段代码使用不规范。
2.原因
2.1 挂死处
查看C++11 thread类实现的源码,可以看到当线程对象析构时,会检查线程的joinable状态,若为joinable,则会调用terminate抛出异常,也就是terminate called without an active exception。
~thread() _NOEXCEPT
{ // clean up
if (joinable())
_XSTD terminate();
}
2.2 线程对象状态及转换
C++11中,线程对象(std::thread)创建后,有两种状态:joinable、
nonjoinable。
代表该线程是否是可执行状态。
joinable : 代表该线程是可执行线程。
nonjoinable:该线程为非不可执行线程,通常一下几种情况会导致线程成为nonjoinable。
1) 由thread的缺省构造函数构造而成(thread()没有参数)。
2) 该thread被move过(包括move构造和move赋值)
3) 该线程调用过join或者detach
其中线程状态经过join或者detach后,将从joinable状态转化为nonjoinable状态。可以看到,我这边的代码并没有进行join或detach,所以当线程对象析构时,将发生上述挂死问题。
3.解决思路
思考了以下几种解决方法:
1.detach线程,将线程分离,线程将自行负责资源回收等操作,但缺点也很明显,当分离线程中存在与父线程一起使用的共享资源,在父线程被销毁后,分离线程继续使用,会发生程序崩溃等问题。
2.join线程,阻塞式等待,缺点同样明显,如果线程长时间未结束,则需要等待很久,阻塞程序。
3.将需要异步线程中执行的业务,统一放到线程池中执行,则能避免上述问题!
最后,统一选择使用线程池执行异步任务。