В следующем классе рабочий поток запускается внутри конструктора. У рабочего есть блокирующий вызов очереди.
Он работает, как и ожидалось, но когда объект 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:
...
...
};
: impl_thread_(&AsyncQueue::worker, this)
. Проблема в том, что если позже в конструкторе возникнет исключение (например, изnew
), может быть вызван деструктор потока joinableimpl_thread_
, что приведет кstd::terminate
. - person Daniel Langr   schedule 07.02.2020tq_
до того, как этот элемент также будет гарантированно установлен. Кроме того, есть ли особая причина, по которойtq_
является общим указателем? Просто используйте простой объект. При объявлении доimpl_thread_
вы также разрешаете условие гонки. - person Ulrich Eckhardt   schedule 07.02.2020