views:

2351

answers:

3

Hello,

Is there any way to integrate Boost.Asio with Qt4 (prefered) or GTK main loop? GTK provides poll(2) like API so technically is should be possible. Qt provides its own networking layer, however I prefer to use existing code written for Boost.Asio. I want to integrate them without using an additional thread.

Is there any reference how to do this for Qt4 (prefered) or GTKmm?

Thanks.

Edit

I want to clearify several things to make the ansver easier. Both Qt and GTKmm provide "select like" functionality:

So, the question is, how to integrate existing "selectors/pollers" as reactor to Boost.Asio io_service. Today, Boost.Asio can use select, kqueue, epoll, /dev/poll and iocp as reactor/proactor service. I want to integrate it to the main-loop of GUI framework.

Any suggestions and solutions (better) are wellcome.

+4  A: 

If I understand your question correctly, you have code written for Boost.Asio . You would like to use that code inside a GUI application.

What is not clear in your question is if you want to wrap the Qt/Gtk network layers through asynio for your code to work, if you are just looking for a solution for having both a gui event loop and asynio together.

I will assume the second case.

Both Qt and Gtk have methods to integrate foreign events in their event loop. See for example qtgtk where the Qt event loop is plugged into Gtk.

In the specific case of Qt, if you want to generate events for Qt, you can use the following class: QAbstractEventDispatcher.

After a quick look at boost asio, I think you need to do the following:

  • have a recurring QTimer with duration zero that calls io_service::run() all the time. That way, boost::asio will call your completion handler as soon as your asynchronous operation is completed.
  • in your completion handler, two options:
    • if your completion operation is a long one, separated from the GUI, do your business and make sure to call qApp.processEvents() regularly to keep the GUI responsive
    • if you just want to communicate back with the gui:
      1. define a custom QEvent type
      2. subscribe to this event
      3. post your event to Qt event loop using QCoreApplication::postEvent().
Bluebird75
The solution you suggest requires some kind of busy or short timeouts wait, that is suboptimal. I rather want merge both even loop and not run-qt/run-asio/run-qt/run-asio, especially when I wait for one of: user input/input from the network that can occure simultaniously.
Artyom
There Ain't No Free Lunch. If I understood correctly, asio has an essential part which is calling the ::run() function, which is blocking. If that function is blocking, either you call it from a background thread, or it might block your application.You mention event loop integration but from quickly browsing, I haven't found any event loop in asio. Asynchronous calling does not necessarily go with an event loop.
Bluebird75
You can also do it the other way round: use Qt for everything, and just "convert" qt network events into a format expected by asio. In this way, you would not use asio, but would have to call the legacy code in the same asio used to do.
Bluebird75
+1 so a workable solution gets something.
eed3si9n
+4  A: 

Simple: Build a slot that calls the gui io_service's poll_one() method. Connect that slot to QT's tick signal.

In Depth: Luckily for you boost asio is very well designed. You have many options on how to provide a thread of execution to the underlying asynchronous internals. People have already mention using io_service::run(). A blocking call with many disadvantages.

You are only allowed to access gui widgets from a single thread. External threads generally need to post events to the gui if they want to do some work on the widget. This is very similar to how asio works.

The naive approach is to just dedicate one thread (or timer) to running io_service::run() and have the asio completion handler post a gui signal. This will work.

Instead you can use the guarantee that completion handlers will only be called in the thread of execution of the io_service caller. Don't have the gui thread call io_service::run as it is blocking and could stall the gui. Instead use io_service::poll() or io_service::poll_one(). This will cause any pending asio completion handlers to be called from the gui thread. Since the handlers are running in the gui thread they are free to modify the widgets.

Now you need make sure the io_service gets a chance to run regularly. I recommend having a repeating gui signal call poll_one() a few times. I believe QT has a tick signal that would do the trick. You could of course roll your own qt signal for more control.

caspin
A: 

Genuinely integrating the main loops is possible. It's just a big pain (and I have yet to actually try it).

Running io_service::run() on a separate thread is probably the way to go.

Nicolás