如何在GUI框架中集成Boost.Asio主循环,如Qt4或GTK

Art*_*yom 27 gtk qt4 event-loop boost-asio

有没有办法将Boost.Asio与Qt4(首选)或GTK主循环集成?GTK像API一样提供poll(2),因此技术上应该是可行的.Qt提供了自己的网络层,但我更喜欢使用为Boost.Asio编写的现有代码.我想在使用额外线程的情况下集成它们.

有没有参考如何为Qt4(首选)或GTKmm做这个?

谢谢.

编辑

我想澄清一些事情,以使答案更容易.Qt和GTKmm都提供"选择类似"功能:

所以,问题是,如何将现有的"选择器/轮询器"作为反应器集成到Boost.Asio中io_service.今天,Boost.Asio可以使用select,kqueue,epoll,/ dev/poll和iocp作为reactor/proactor服务.我想将它集成到GUI框架的主循环中.

欢迎任何建议和解决方案(更好).

def*_*ode 15

简单: 构建一个调用io_service::poll_one()属于gui 的QT槽.将该插槽连接到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().这将导致从gui线程调用任何挂起的Asio完成处理程序.由于处理程序在gui线程中运行,因此可以自由修改小部件.

现在你需要确保io_service有机会定期运行.我建议重复poll_one()几次gui信号呼叫.我相信QT有一个滴答信号可以解决问题.您当然可以滚动自己的QT信号以获得更多控制.

  • 什么"滴答"信号?听起来这会让ASIO做繁忙的等待会导致高CPU使用率. (3认同)

pep*_*er0 9

这是一个相当古老的问题,但对于那些正在阅读它的人,我想分享我的代码,这是一个用于boost :: asio的QAbstractEventDispatcher的实现.

您只需在创建QApplication之前添加以下行(通常是在main()中).

QApplication::setEventDispatcher(new QAsioEventDispatcher(my_io_service));
Run Code Online (Sandbox Code Playgroud)

这将导致io_service与qt应用程序一起在一个线程中运行而没有额外的延迟和性能下降(就像在不时调用io_service :: poll()的解决方案中那样).

不幸的是,我的解决方案仅适用于posix系统,因为它使用asio :: posix :: stream_descriptor.Windows支持可能需要完全不同的方法或非常相似 - 我真的不知道.

  • 不幸的是,qt开发人员不推荐这样的解决方案:http://www.qtcentre.org/threads/53229-How-to-integrate-asio-io_service-with-Qt-event-loop. (2认同)

Phi*_*e F 6

如果我正确理解您的问题,您可以为Boost.Asio编写代码.您希望在GUI应用程序中使用该代码.

你的问题中不清楚的是,如果你想通过asynio包装Qt/Gtk网络层以使代码工作,如果你只是想找到一个同时拥有gui事件循环和asynio的解决方案.

我将假设第二种情况.

Qt和Gtk都有将方法集成到事件循环中的方法.例如,参见qtgtk,其中Qt事件循环插入到Gtk中.

在Qt的特定情况下,如果要为Qt生成事件,可以使用以下类:QAbstractEventDispatcher.

快速浏览一下boost asio后,我认为您需要执行以下操作:

  • 有一个持续时间为零的重复QTimer,它始终调用io_service :: run().这样,boost :: asio将在异步操作完成后立即调用完成处理程序.
  • 在完成处理程序中,有两个选项:
    • 如果你的完成操作很长,与GUI分开,那就做你的业务,并确保定期调用qApp.processEvents()以保持GUI响应
    • 如果你只是想与gui沟通:
      1. 定义自定义QEvent类型
      2. 订阅此活动
      3. 使用QCoreApplication :: postEvent()将您的事件发布到Qt事件循环.

  • 你建议的解决方案需要某种繁忙或短暂的超时等待,这是次优的.我宁愿合并甚至循环而不是run -qt/run-asio/run-qt/run-asio,特别是当我等待其中一个:来自网络的用户输入/输入可能同时发生. (2认同)