Cómo integrar el bucle principal de Boost.Asio en el marco GUI como Qt4 o GTK
boost-asio event-loop (4)
Es una pregunta bastante antigua, pero para aquellos que la están leyendo ahora me gustaría compartir mi código, que es una implementación de QAbstractEventDispatcher para boost :: asio.
Todo lo que necesita es agregar la siguiente línea antes de crear QApplication (generalmente está en main ()).
QApplication::setEventDispatcher(new QAsioEventDispatcher(my_io_service));
Esto causará que io_service se ejecute junto con la aplicación qt en un subproceso sin una latencia adicional y una caída del rendimiento (como en la solución con llamadas a io_service :: poll () "de vez en cuando").
Desafortunadamente, mi solución es solo para sistemas posix, ya que usa asio :: posix :: stream_descriptor. El soporte de Windows puede necesitar un enfoque completamente diferente o bastante similar, no lo sé.
¿Hay alguna forma de integrar Boost.Asio con Qt4 (preferido) o el ciclo principal de GTK? GTK proporciona una encuesta (2) como API, por lo que técnicamente debería ser posible. Qt proporciona su propia capa de red, sin embargo, prefiero usar el código existente escrito para Boost.Asio. Quiero integrarlos sin usar un hilo adicional.
¿Hay alguna referencia sobre cómo hacer esto para Qt4 (preferido) o GTKmm?
Gracias.
Editar
Quiero aclarar varias cosas para facilitar la respuesta. Tanto Qt como GTKmm proporcionan la funcionalidad "seleccionar como":
- http://qt-project.org/doc/qt-5.0/qtcore/qsocketnotifier.html
- http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/group__MainLoop.html
Entonces, la pregunta es cómo integrar los "selectores / sondeos" existentes como reactor a Boost.Asio io_service
. Hoy, Boost.Asio puede usar select, kqueue, epoll, / dev / poll y iocp como servicio de reactor / proactor. Quiero integrarlo en el bucle principal del marco GUI.
Cualquier sugerencia y solución (mejor) son bienvenidas.
La integración genuina de los bucles principales es posible. Es solo un gran dolor (y todavía tengo que intentarlo).
Ejecutar io_service :: run () en un hilo separado es probablemente el camino a seguir.
Si entiendo su pregunta correctamente, tiene un código escrito para Boost.Asio. Le gustaría usar ese código dentro de una aplicación GUI.
Lo que no queda claro en su pregunta es si desea ajustar las capas de red Qt / Gtk a través de asynio para que su código funcione, si solo está buscando una solución para tener un bucle de eventos gui y asynio juntos.
Asumiré el segundo caso.
Tanto Qt como Gtk tienen métodos para integrar eventos externos en su bucle de eventos. Vea, por ejemplo, qtgtk donde el bucle de eventos Qt está conectado a Gtk.
En el caso específico de Qt, si desea generar eventos para Qt, puede usar la siguiente clase: QAbstractEventDispatcher .
Después de un vistazo rápido a boost asio, creo que necesitas hacer lo siguiente:
- tiene un QTimer recurrente con duración cero que llama a io_service :: run () todo el tiempo. De esa manera, boost :: asio llamará a su controlador de finalización tan pronto como se complete su operación asíncrona.
- en su controlador de finalización, dos opciones:
- Si su operación de finalización es larga, separada de la GUI, haga su trabajo y asegúrese de llamar a qApp.processEvents () regularmente para mantener la GUI receptiva
- Si solo quieres comunicarte con el GUI:
- define un tipo de QEvent personalizado
- suscribirse a este evento
- publique su evento en el bucle de eventos Qt utilizando QCoreApplication::postEvent() .
Simple: construya una ranura QT que llame al io_service::poll_one()
pertenece a la interfaz io_service::poll_one()
. Conecte esa ranura a la señal de tick
de QT.
En profundidad: Afortunadamente para ti, Boost.Asio está muy bien diseñado. Hay muchas opciones sobre cómo proporcionar un hilo de ejecución a las partes internas asíncronas subyacentes. La gente ya ha mencionado el uso de io_service::run()
, una llamada de bloqueo con muchas desventajas.
Solo se le permite acceder a los widgets de GUI desde un solo hilo. Los subprocesos externos generalmente necesitan publicar eventos en la interfaz gráfica de usuario si quieren mutar cualquier widget. Esto es muy similar a cómo funciona Asio.
El enfoque ingenuo es dedicar un hilo (o temporizador) a la ejecución de io_service::run()
y hacer que el controlador de finalización de Asio publique una señal gui. Esto funcionará.
En su lugar, puede utilizar la garantía de que los manejadores de finalización solo serán llamados en el hilo de ejecución del llamador io_service
. No tenga la llamada gui thread io_service::run()
ya que está bloqueando y podría colgar la gui. En su lugar, use io_service::poll()
o io_service::poll_one()
. Esto hará que se llame a cualquier controlador de finalización de Asio pendiente desde el hilo gui. Como los manejadores se ejecutan en el hilo de la interfaz gráfica de usuario, pueden modificar los widgets.
Ahora necesita asegurarse de que io_service
tenga la oportunidad de ejecutarse con regularidad. Recomiendo tener una señal gui de repetición, llame a poll_one()
unas cuantas veces. Creo que QT tiene una señal de tick que haría el truco. Por supuesto, podrías rodar tu propia señal QT para tener más control.