事件经过
在编写一个包含了线程使用的SDK接口时,原以为只需要在析构当中添加等待线程执行完成的逻辑即可。但是在编写过程中,为了节约资源,添加了一个lamba表达式使得线程在不使用时则暂停执行;而且还将线程中的循环条件直接写成了 while(true) 。
在大多数情况下,这个API接口用户很多时候并不会通过我们给出的 Close() 接口进行正常的程序终止,而是直接 “终止进程”、“shutdown” 抑或是 “断电”… 然而一次偶然的新功能添加,我们需要单独的在一个函数当中使用SDK库。为了保证SDK的实例接口在函数退出后,SDK中的回调不会因为保留了一个已经不存在的指针,因此我们必须采用 Close() 接口进行一次注销。然而在注销过程中,由于我写的线程为 while(true) ,并且通过了条件变量中的 lamba 表达式使得线程处在一个休眠状态,从而导致函数在析构后,线程一直无法退出。
总的来说,就是没有给到线程一个正常的退出机制。就和《无间道》里面朝伟哥一样,被派出去了,却一直没有得到结束任务的指令?
代码示例
ClassA::ClassA()
{
Thread_ = new std::thread(std::bind(&ClassA::service, this)); //创建一个线程
}
ClassA::~ClassA()
{
// 原本的方法
// if(Thread_ != nullptr) {
// Thread_->detach();
// delete Thread_;
// Thread_ = nullptr;
// }
// 改动后
quit_thread_ = true; //在创建时,将此变量置为false
if(Thread_->jointable()) {
Thread_->joint();
}
}
void ClassA:service()
{
// while(true) { // 原本的写法
while(!quit_thread_) {
std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_SLEEP));
std::unique_lock<std::mutex> lock(m_interfaceMutexPtr);
// 这里使用了一个条件变量进行了阻塞,原本的写法。
// m_interfaceConditonPtr.wait(lock, [this]() {
// return !is_empty;
// });
// 新的方法中,增加了一下条件等待超时。实际上是不是他也还是会导致出现同样的结果呢?还需要测试,起码现在他是可以退出了。
m_interfaceConditonPtr.wait_for(lock, std::chrono::milliseconds(TIME_OUT), [this]
{
return !o_O; // 尊嘟假嘟 ?
})
}
}
总结
通过这一次问题,实际上也排出了一些埋藏在整个架构中当中多年的雷,我的这个错误只是其中一个,也可以说是一个照明弹了。出现这种问题,总的来说还是自己对于线程这方面的基础功还是不够扎实。还得继续努力攒经验啊!
不知道为啥,最近工作量明明不大,但是就是好累啊!各种方面上的累。