Как интегрировать Boost.Основной цикл Asio в GUI framework, такой как Qt4 или GTK

StackOverflow https://stackoverflow.com/questions/1001032

Вопрос

Есть ли какой-либо способ интегрировать Boost.Asio с Qt4 (предпочтительно) или GTK main loop?GTK предоставляет poll (2), подобный API, так что технически это должно быть возможно.Qt предоставляет свой собственный сетевой уровень, однако я предпочитаю использовать существующий код, написанный для Boost.Asio.Я хочу объединить их без используя дополнительный поток.

Есть ли какая-нибудь ссылка, как это сделать для Qt4 (предпочтительно) или GTKmm?

Спасибо.

Редактировать

Я хочу прояснить несколько вещей, чтобы упростить ответ.И Qt, и GTKmm предоставляют функциональность "выбрать понравившееся":

Итак, вопрос в том, как интегрировать существующие "селекторы / опросчики" в качестве реактора для Boost.Asio io_service.Сегодня запускаем Boost.Asio может использовать select, kqueue, epoll, /dev/poll и iocp в качестве службы reactor / proactor.Я хочу интегрировать его в основной цикл GUI framework.

Любые предложения и решения (лучше) приветствуются.

Это было полезно?

Решение

Это довольно старый вопрос, но для тех, кто читает его сейчас, я хотел бы поделиться мой код который является реализацией QAbstractEventDispatcher для boost::asio.

Все, что вам нужно, это добавить следующую строку перед созданием QApplication (обычно это в main()).

QApplication::setEventDispatcher(new QAsioEventDispatcher(my_io_service));

Это приведет к тому, что io_service будет запускаться вместе с приложением qt в одном потоке без дополнительной задержки и снижения производительности (как в решении с вызовом io_service::poll() "время от времени").

К сожалению, мое решение предназначено только для систем posix, поскольку оно использует asio::posix::stream_descriptor .Службе поддержки Windows может потребоваться совершенно другой подход или очень похожий - я действительно не знаю.

Другие советы

Простой: Создайте слот QT , который вызывает io_service::poll_one() принадлежащий графическому интерфейсу.Подключите этот слот к QT's tick сигнал.

В Глубине: К счастью для вас, Boost.Asio очень хорошо разработан.Существует много вариантов того, как предоставить поток выполнения базовым асинхронным внутренним устройствам.Люди уже упоминали об использовании io_service::run(), блокирующий вызов со многими недостатками.

Вам разрешен доступ к виджетам gui только из одного потока.Внешним потокам обычно необходимо публиковать события в графическом интерфейсе, если они хотят изменить какой-либо виджет.Это очень похоже на то, как работает Asio.

Наивный подход заключается в том, чтобы просто выделить один поток (или таймер) для запуска io_service::run() и пусть обработчик завершения Asio отправит сигнал gui.Это будет работать.

Вместо этого вы можете использовать гарантию того, что обработчики завершения будут вызываться только в потоке выполнения io_service звонивший.У вас нет вызова потока gui io_service::run() так как это блокирует и может привести к зависанию графического интерфейса.Вместо этого используйте io_service::poll() или io_service::poll_one().Это приведет к вызову всех ожидающих завершения обработчиков Asio из потока gui.Поскольку обработчики выполняются в потоке gui, они могут свободно изменять виджеты.

Теперь вам нужно убедиться, что io_service получает возможность регулярно бегать.Я рекомендую использовать повторяющийся вызов сигнала gui poll_one() несколько раз.Я считаю, что у QT есть тиковый сигнал, который бы сделал свое дело.Конечно, вы могли бы создать свой собственный QT-сигнал для большего контроля.

Если я правильно понял ваш вопрос, у вас есть код, написанный для Boost.Asio .Вы хотели бы использовать этот код внутри приложения с графическим интерфейсом.

Что неясно в вашем вопросе, так это то, хотите ли вы обернуть сетевые уровни Qt / Gtk через asynio, чтобы ваш код работал, если вы просто ищете решение для совместного использования цикла событий gui и asynio.

Я возьму на себя второй случай.

И Qt, и Gtk имеют методы для интеграции внешних событий в свой цикл событий.Смотрите, например qtgtk ( ктгтк ) где цикл событий Qt подключен к Gtk.

В конкретном случае Qt, если вы хотите генерировать события для Qt, вы можете использовать следующий класс: QAbstractEventDispatcher.

После беглого ознакомления с boost asio, я думаю, вам нужно сделать следующее:

  • имейте повторяющийся QTimer с нулевой длительностью, который постоянно вызывает io_service::run().Таким образом, boost::asio вызовет ваш обработчик завершения, как только ваша асинхронная операция будет завершена.
  • в вашем обработчике завершения есть два варианта:
    • если ваша операция завершения длинная и отделена от графического интерфейса, занимайтесь своими делами и обязательно регулярно вызывайте qApp.processEvents(), чтобы графический интерфейс оставался отзывчивым
    • если вы просто хотите связаться с графическим интерфейсом:
      1. определите пользовательский Событие Тип
      2. подпишитесь на это событие
      3. разместите свое событие в цикле событий Qt, используя QCoreApplication::postEvent() QCoreApplication::postEvent().

Подлинная интеграция основных циклов является возможно.Это просто большая боль (и мне еще предстоит это попробовать).

Вероятно, лучше всего запустить io_service::run() в отдельном потоке.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top