Как интегрировать основной цикл Boost.Asio в инфраструктуру GUI, такую ​​как Qt4 или GTK - PullRequest
27 голосов
/ 16 июня 2009

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

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

Спасибо.

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

Я хочу уточнить несколько вещей, чтобы облегчить ответ. И Qt, и GTKmm обеспечивают Функциональность «выберите как»:

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

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

Ответы [ 4 ]

15 голосов
/ 21 декабря 2009

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

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

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

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

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

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

9 голосов
/ 15 декабря 2014

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

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

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

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

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

6 голосов
/ 19 июня 2009

Если я правильно понимаю ваш вопрос, у вас есть код, написанный для 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. определить пользовательский QEvent тип
      2. подписаться на это событие
      3. отправьте ваше событие в цикл событий Qt, используя QCoreApplication :: postEvent () .
2 голосов
/ 23 декабря 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...