Я использую boost :: asio, чтобы выполнить базовый сбор пакетов UDP. Объект io_service создается в рабочем потоке, и io_service.run () вызывается из этого потока. Моя проблема в том, что io_service.run () возвращается, когда я закончу собирать пакеты.
Мне не ясно, какие методы io_service можно вызывать из других потоков, когда приходит время остановить мой рабочий поток. У меня есть ссылка на объект io_service, и из другого потока я делаю этот вызов:
ios.dispatch( boost::bind( &udp_server::handle_kill, this ) );
В моем классе udp_server обработчик для этой функции отменяет ожидающую работу из одного объекта boost :: asio :: ip :: udp :: socket и одного объекта boost :: asio :: deadline_timer. Оба ожидают выполнения асинхронной работы. В этот момент я вызываю ios.stop ():
void udp_server::handle_kill()
{
m_socket.cancel();
m_timer.cancel();
m_ios.stop();
}
Пока работа не ожидается, я ожидаю, что мой вызов ios.run () должен вернуться, но этого не происходит.
Так почему же он не возвращается? Наиболее вероятным объяснением для меня является то, что я не должен вызывать io_service :: dispatch () из другого потока. Но метод dispatch (), похоже, создан для того, чтобы делать это - отправлять вызов функции в потоке, в котором работает io_service :: run (). И, похоже, именно это и делается.
Так что это оставляет меня с несколькими связанными вопросами:
- Правильно ли я использую io_service :: dispatch ()?
- Если все задачи отменены, есть ли причина, по которой io_service :: run () не должен возвращаться?
- socket :: upd :: cancel () не является правильным способом закрыть сокет и прервать всю работу. Какой правильный путь?
asio ведет себя довольно хорошо для меня, но мне нужно лучше понять эту часть архитектуры.
Больше данных
socket :: udp :: cancel (), по-видимому, является неподдерживаемой операцией на открытом сокете под Win32 - поэтому эта операция завершается ошибкой, вызывая исключение - что фактически вызывает выход из io_service :: run (), но определенно не желаемый выход.
socket :: udp :: close (), похоже, не отменяет отложенную задачу async_receive_from (), поэтому ее вызов вместо socket :: udp :: cancel (), кажется, оставляет поток где-то внутри io_service :: run ().