Я использую 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. Оба имеют ожидающую работу async. В этот момент я вызываю 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(), поэтому вызов его вместо сокета:: udp:: cancel(), кажется, оставляет поток где-то внутри io_service:: run().