如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?



在下面的类中,在构造函数中启动了一个工作线程。 工作线程具有对队列的阻止调用。

它按预期工作,但是当AsyncQueue对象超出范围(无论出于何种原因(时,将调用其析构函数。此外,调用simple_queue对象的析构函数(我通过调试检查的内容(。

但是工人会怎样呢?因为它仍在等待队列的阻塞调用!

我观察到,在析构函数执行中没有调用impl_thread_.detach();就会崩溃。 但是,我不知道这是否是一种解决方案。我还不明白的是:尽管队列对象被销毁,但阻塞调用不会引发异常 - 实际上我在 catch 处理程序中设置了一个断点。那么这里发生了什么,实现这种情况的正确方法是什么?我深深地感觉到,我在这里所做的并不完全是应有的;-(

template<typename T>
class AsyncQueue
{
public:
AsyncQueue() : impl_thread_(&AsyncQueue::worker, this)
{
tq_ = std::shared_ptr<simple_queue<T>>(new simple_queue<T>);
impl_thread_.detach();
}
//~AsyncQueue() = default;
~AsyncQueue() {
std::cout << "[" << boost::this_thread::get_id() << "] destructor AsyncQueue" << std::endl;
return;
}
private:
std::thread impl_thread_;
std::shared_ptr<simple_queue<T>> tq_;
void worker()
{
try {
while (true)
{
boost::optional<T> item = tq_->deq(); // blocks
...
...
...
}
}
catch (exception const& e) {
return;
}
}
public:
...
...

};

如果可以的话,最简单的方法是在析构函数中发送 eq 队列中的停止令牌,并检查工作线程中的停止令牌以退出它。首先删除分离。

~AsyncQueue() {
_eq.add(stopToken); // what ever your can use here. else use an atomic bool 
std::cout << "[" << boost::this_thread::get_id() << "] destructor AsyncQueue" << std::endl;
impl_thread_.join();
}

(未经测试,不完整(

最新更新