c++ - Boost asio-detener io_service
boost-asio (1)
Estoy usando boost :: asio para hacer una colección de paquetes UDP muy básica. El objeto io_service se crea una instancia en un subproceso de trabajo, y se llama a io_service.run () desde ese subproceso. Mi problema es conseguir que io_service.run () regrese cuando termine de recolectar los paquetes.
No tengo claro qué métodos de io_service se pueden invocar desde otros hilos cuando llega el momento de detener mi hilo de trabajo. Tengo una referencia al objeto io_service, y de un hilo diferente hago esta llamada:
ios.dispatch( boost::bind( &udp_server::handle_kill, this ) );
En mi clase udp_server, el controlador para esa función cancela el trabajo pendiente desde un solo boost :: asio :: ip :: udp :: socket y un único boost :: asio :: deadline_timer object. Ambos tienen pendiente el trabajo asincrónico por hacer. En ese momento, llamo a ios.stop ():
void udp_server::handle_kill()
{
m_socket.cancel();
m_timer.cancel();
m_ios.stop();
}
Sin trabajos pendientes, espero que mi llamada a ios.run () vuelva en este momento, pero esto no sucede.
Entonces, ¿por qué no regresa? La explicación más probable para mí es que no debería llamar a io_service :: dispatch () desde otro hilo. Pero el método dispatch () parece que fue creado para hacer justamente eso: despachar una llamada de función en el hilo en el que io_service :: run () está trabajando. Y parece hacer precisamente eso.
Entonces esto me deja con algunas preguntas relacionadas:
- ¿Estoy usando io_service :: dispatch () correctamente?
- Si se cancelan todas las tareas, ¿hay alguna razón por la que io_service :: run () no deba regresar?
- socket :: upd :: cancel () no parece ser la forma correcta de cerrar un socket y cancelar todo el trabajo. ¿Cuál es la manera correcta?
asio se está comportando bastante bien para mí, pero necesito entender mejor este poco de arquitectura.
Más datos
socket :: udp :: cancel () es aparentemente una operación no compatible en un socket abierto bajo Win32 - por lo que esta operación falla lanzando una excepción - que de hecho causa una salida de io_service :: run (), pero definitivamente no es el deseado salida.
socket :: udp :: close () no parece cancelar la tarea pendiente async_receive_from (), por lo que al llamarlo en lugar de socket :: udp :: cancel () parece dejar el hilo en algún lugar dentro de io_service :: run ().
Invocar io_service::stop
desde otro subproceso es seguro, esto está bien descrito en la documentación
Seguridad de subprocesos
Objetos distintos : seguro.
Objetos compartidos : seguro, con la excepción de que llamar a reiniciar () mientras hay ejecuciones sin ejecutar run (), run_one (), poll () o poll_one () da como resultado un comportamiento indefinido.
como indican los comentarios a su pregunta, realmente necesita reducir esto a un ejemplo reproducible.