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

在下面的类中,工作线程在构造函数中启动。 工作人员对队列的阻塞调用。

It works as expected, but when the AsyncQueue object gets out of scope (for whatever reason), its destructor is called. Also, the destructor of the simple_queue object is called (what I checked by debugging).

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

I observed, that without calling impl_thread_.detach(); within the destructor execution crashes. However, I don't know whether this is a solution at all. What I don't understand additionally: although the queue object is destroyed the blocking call is not raising an exception - in fact I set a break-point in the catch handler. So what is going on here and what is the right way to implement that scenario? I deeply feel, that what I do here is not quite as it should be ;-)

    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队列中发送停止令牌,然后在worker中检查该停止令牌以退出该令牌。首先卸下分离器。

    ~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();
      return;
    }