Повышение asio - остановка io_service - PullRequest
18 голосов
/ 26 января 2011

Я использую 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 (). И, похоже, именно это и делается.

Так что это оставляет меня с несколькими связанными вопросами:

  1. Правильно ли я использую io_service :: dispatch ()?
  2. Если все задачи отменены, есть ли причина, по которой io_service :: run () не должен возвращаться?
  3. socket :: upd :: cancel () не является правильным способом закрыть сокет и прервать всю работу. Какой правильный путь?

asio ведет себя довольно хорошо для меня, но мне нужно лучше понять эту часть архитектуры.

Больше данных

socket :: udp :: cancel (), по-видимому, является неподдерживаемой операцией на открытом сокете под Win32 - поэтому эта операция завершается ошибкой, вызывая исключение - что фактически вызывает выход из io_service :: run (), но определенно не желаемый выход.

socket :: udp :: close (), похоже, не отменяет отложенную задачу async_receive_from (), поэтому ее вызов вместо socket :: udp :: cancel (), кажется, оставляет поток где-то внутри io_service :: run ().

1 Ответ

24 голосов
/ 27 января 2011

Вызов io_service::stop из другого потока безопасен, это хорошо описано в документации

Резьба безопасности

Отдельные объекты : Сейф.

Общие объекты : Сейф, с исключение, что вызов reset () в то время как есть незавершенные run (), run_one (), Вызов poll () или poll_one () приводит к неопределенное поведение.

Как показывают комментарии к вашему вопросу, вам действительно нужно свести это к воспроизводимому примеру.

...