【发布时间】:2020-05-23 09:20:53
【问题描述】:
在下面的类中,工作线程在构造函数中启动。 工作人员对队列有阻塞调用。
它按预期工作,但是当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:
...
...
};
【问题讨论】:
-
问题 OT:我认为这不是一个安全的话题开始方式:
: impl_thread_(&AsyncQueue::worker, this)。问题是,如果稍后在构造函数中抛出异常(例如来自new),可能会调用joinable线程impl_thread_的析构函数,从而导致std::terminate。 -
不要添加没有任何值的代码(这两个在析构函数和 catch 块中返回)。无论如何,只要运行最后一个表达式,您就会从函数返回。
-
您的线程启动并访问
tq_,然后保证也设置该成员。另外,tq_是共享指针是否有特殊原因?只需使用一个普通的对象。在impl_thread_之前声明时,您还解决了竞争条件。 -
@Ulrich:是的,你是对的。然而,修改构造函数并不能解决我的问题,这与破坏更相关。也不使用普通对象而不是共享指针。
标签: c++ multithreading destructor stdthread blockingqueue