Как остановить / уничтожить поток с помощью вызова блокировки изящно при вызове деструктора C ++? - PullRequest
1 голос
/ 07 февраля 2020

В следующем классе рабочий поток запускается в конструкторе. У работника есть блокирующий вызов в очередь.

Он работает, как и ожидалось, но когда объект AsyncQueue выходит из области видимости (по какой-либо причине), вызывается его деструктор. Также вызывается деструктор объекта simple_queue (что я проверил отладкой).

Но что происходит с рабочим? Поскольку он все еще ожидает блокирующего вызова в очередь!

Я заметил, что без вызова impl_thread_.detach(); внутри деструктора происходит сбой. Однако я не знаю, является ли это решением вообще. Что я не понимаю дополнительно: хотя объект очереди уничтожен, блокирующий вызов не вызывает исключение - фактически я установил точку останова в обработчике перехвата. Итак, что здесь происходит и как правильно реализовать этот сценарий? Я глубоко чувствую, что то, что я делаю здесь, не совсем так, как должно быть; -)

    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:
    ...
    ...


    };

1 Ответ

2 голосов
/ 07 февраля 2020

Самый простой способ, если вы можете, - это использовать в деструкторе отправку стоп-токена в очереди эквалайзера и проверить стоп-токен в работнике для его выхода. Сначала удалите отсоединение.

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

(непроверенный, неполный)

...