Как интегрировать основной цикл Boost.Asio в инфраструктуре графического интерфейса, например Qt4 или GTK
Есть ли способ интегрировать Boost.Asio с Qt4 (предпочтительный) или основной цикл GTK?
GTK предоставляет опрос (2), такой как API, поэтому технически это должно быть возможно. Qt предоставляет свой собственный сетевой уровень, однако я предпочитаю использовать существующий код, написанный для Boost.Asio.
Я хочу интегрировать их без, используя дополнительный поток.
Есть ли какая-нибудь ссылка, как это сделать для Qt4 (предпочтительный) или GTKmm?
Спасибо.
Edit
Я хочу очистить несколько вещей, чтобы облегчить ответ. Оба Qt и GTKmm обеспечивают
функция "select like":
Итак, вопрос заключается в том, как интегрировать существующие "селекторы/опылители" в качестве реактора для
Boost.Asio io_service
. Сегодня Boost.Asio может использовать select, kqueue, epoll,/dev/poll и iocp в качестве службы реакторов/проакторов. Я хочу интегрировать его в основной цикл графического интерфейса.
Любые предложения и решения (лучше) приветствуются.
Ответы
Ответ 1
Это довольно старый вопрос, но для тех, кто сейчас его читает, я хотел бы поделиться моим кодом, который является реализацией QAbstractEventDispatcher для boost:: asio.
Все, что вам нужно, это добавить следующую строку перед созданием QApplication (обычно это в main()).
QApplication::setEventDispatcher(new QAsioEventDispatcher(my_io_service));
Это приведет к тому, что io_service запускается вместе с qt-приложением в одном потоке без дополнительной задержки и снижения производительности (например, в решении с вызовом io_service:: poll() "время от времени" ).
К сожалению, мое решение предназначено только для систем posix, так как оно использует asio:: posix:: stream_descriptor. Для поддержки Windows может потребоваться совершенно другой подход или совсем аналогичный - я действительно не знаю.
Ответ 2
Простой:
Создайте слот QT, который вызывает io_service::poll_one()
, принадлежащий gui. Подключите этот слот к сигналу QT tick
.
В глубине:
К счастью для вас Boost.Asio очень хорошо спроектирован. Существует множество опций о том, как обеспечить поток выполнения для основных асинхронных внутренних компонентов. Люди уже упоминают использование io_service::run()
, блокирующий вызов со многими недостатками.
Вам разрешен доступ к виджетам gui из одного потока. Внешние потоки обычно должны отправлять события в gui, если они хотят сделать мутацию любого виджета. Это очень похоже на то, как работает Asio.
Наивный подход состоит в том, чтобы просто выделить один поток (или таймер) для запуска io_service::run()
и обработчик завершения Asio отправит сигнал gui. Это будет работать.
Вместо этого вы можете использовать гарантию, что обработчики завершения будут вызываться только в потоке выполнения вызывающего io_service
. У вас нет потока вызовов gui io_service::run()
, поскольку он блокирует и может висеть gui. Вместо этого используйте io_service::poll()
или io_service::poll_one()
. Это приведет к вызову любых обработчиков завершения Asio, которые будут вызваны из потока gui. Поскольку обработчики работают в потоке gui, они могут изменять виджеты.
Теперь вам нужно убедиться, что io_service
получает возможность регулярно запускаться. Я рекомендую несколько раз повторить вызов сигнала gui poll_one()
. Я считаю, что QT имеет сигнал тика, который бы сделал трюк. Вы могли бы, конечно, свернуть свой собственный сигнал QT для большего контроля.
Ответ 3
Если я правильно понял ваш вопрос, у вас есть код, написанный для Boost.Asio. Вы хотите использовать этот код внутри приложения GUI.
В вашем вопросе непонятно, хотите ли вы обрезать сетевые уровни Qt/Gtk через asynio, чтобы ваш код работал, если вы просто ищете решение для объединения циклов событий gui и asynio.
Я возьму второй случай.
Оба Qt и Gtk имеют методы для интеграции иностранных событий в их цикл событий. См. Например qtgtk, где цикл событий Qt подключен к Gtk.
В конкретном случае Qt, если вы хотите генерировать события для Qt, вы можете использовать следующий класс: QAbstractEventDispatcher.
После быстрого просмотра boost asio, я думаю, вам нужно сделать следующее:
- имеют повторяющийся QTimer с нулевой длительностью, который вызывает io_service:: run() все время. Таким образом, boost:: asio будет вызывать ваш обработчик завершения, как только ваша асинхронная операция будет завершена.
- в вашем обработчике завершения, два варианта:
- если ваша операция завершения является длинной, отделенной от графического интерфейса пользователя, выполняйте свою деятельность и убедитесь, что вы регулярно вызываете qApp.processEvents(), чтобы поддерживать графический интерфейс.
- Если вы просто хотите общаться с gui:
Ответ 4
Возможна интеграция основных петель. Это просто большая боль (и я еще не попробовал).
Запуск io_service:: run() в отдельном потоке - это, вероятно, путь.