【问题标题】:How to stop/destroy a thread with a blocking call gracefully upon call of C++ destructor?如何在调用 C++ 析构函数时优雅地停止/销毁具有阻塞调用的线程?
【发布时间】: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_(&amp;AsyncQueue::worker, this)。问题是,如果稍后在构造函数中抛出异常(例如来自new),可能会调用joinable线程impl_thread_的析构函数,从而导致std::terminate
  • 不要添加没有任何值的代码(这两个在析构函数和 catch 块中返回)。无论如何,只要运行最后一个表达式,您就会从函数返回。
  • 您的线程启动并访问tq_,然后保证也设置该成员。另外,tq_ 是共享指针是否有特殊原因?只需使用一个普通的对象。在impl_thread_ 之前声明时,您还解决了竞争条件。
  • @Ulrich:是的,你是对的。然而,修改构造函数并不能解决我的问题,这与破坏更相关。也不使用普通对象而不是共享指针。

标签: c++ multithreading destructor stdthread blockingqueue


【解决方案1】:

如果可以的话,最简单的方法是在你的析构函数中在你的 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();
}

(未经测试,不完整)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 2016-11-10
    • 1970-01-01
    • 2016-02-01
    • 2011-04-25
    • 2013-11-16
    • 1970-01-01
    相关资源
    最近更新 更多