2

I am trying to use boost::asio async client example with a simple Qt GUI like:

enter image description here

A little snippet from my app:

The button click SLOT:

void RestWidget::restGetCall()
{

    networkService ntwkSer("www.boost.org","80");
    connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)));
    ntwkSer.get("/LICENSE_1_0.txt");

}

The networkService class is just a wrapper of the above linked boost sample code.Its derived from QObject class for signal,slot mechanism.

void networkService::get(const std::string & path)
{
   // boost::thread (boost::bind(&networkService::networkCall,this,path));//this gives me sigabrt
    networkCall(path);//this works fine, and i get output as pictured above.
}

void networkService::networkCall(const std::string path)
{
    tcp::resolver::query query(host_, port_);//also these host,port fields come out to be invalid/garbage.
    //tcp::resolver::query query("www.boost.org","80");//still doesnt resolve the SIGABRT
    resolver_.async_resolve(query,
        boost::bind(&networkService::handle_resolve, this,
        boost::asio::placeholders::error,
        boost::asio::placeholders::iterator,
        path));
    io_service.run();
}

The problem, is when i run the io_service.run() from the boost::thread. i get SIGABRT.

also he host_,port_ networkService wrapper class fields inside the networkService::networkCall(path) function on debugging come out to be invalid, which get saved while constructing:

networkService ntwkSer("www.boost.org","80");

The obvious reason for boost::thread is to make GUI non-blocking,since io_service() has its own eventloop. My intention is to run boost::asio async calls in a seperate boost thread, and notify the GUI thread with QT's Q_OBJECT signal slot mechanism.

I don't get the reason of SIGABRT and also why could the field values of host_ and port_ become invalid once i start using boost::thread.

PS: This same setup, behaves correctly with boost::thread from a similar commandline application (no Qt GUI code), i.e when the networkService class is not hacked for Qt signal/slot to notify the main GUI thread. Here, i use the boost::asio's response from within the boost::thread.

Edit: as per responses to my question, i tried this... i disabled Q_OBJECT signal/slot and QObject derivation of the networkservice class, to be sure MOC isnt messing things up.. but still, the issue prevails, i get access violation on windows vs sigabrt on linux. The issue of the networkservice object's fields getting corrupted is also present, eventually getting access violation. In effect no change in behaviour.

before launching thread: enter image description here from inside thread enter image description here access violation on continue... enter image description here

So, even without MOC , the issue is still there.

Edit 2: Im sorry for bothering.. i did a huge mistake, of using a local networkService object from within the boost::thread, which got scoped out when the thread actually ran!

ashishsony
  • 2,537
  • 3
  • 26
  • 38
  • I've not had a chance to check (apologies for this low value comment), but could it have something to do with the precompilation step in qt? Boost has a lot of complicated header files, and qt does a weird thing to code before gcc is called, might be an opportunity for things to get messed up. On I general note I've always considered it poor form to mix application paradigms; boost asio is proactor, qt is signal slot. Things could get a little confusing! – bazza Sep 14 '16 at 04:44

2 Answers2

2

It's difficult to get the asio io_service.run() function to "play well" with the Qt event loop.

It's easier to use a Qt slot that calls io_service::poll() or io_service::poll_one() and then connect that slot to a QTimerEvent.

And it's even easier to use QNetworkAccessManager instead of asio see Qt Client Example

kenba
  • 4,303
  • 1
  • 23
  • 40
2

The problem is that with qt only one thread is allowed to manipulate the gui in qt. That is the one calling QApplication::exec. This is done to remove complexity for the users of qt and due to that QApplication / message loop being a singleton. That being said there is some magic going on in qt with threads. All QObjects are assigned a thread. By default the one on which they are created. When a signal slot connection is made it is determined how to actually dispatch the call. If the objects belong to the same thread a signal is dispatched by directly / synchronous invoking the slot. If the objects are assigned to distinguished threads a message is send from one thread to another to invoke the slot on the thread that is assigned to the object where the slot lives. This is what you actually need here.

The problem with your code is that both of your QObjects are created on the same thread. They are therefore assigned the same thread. So the slot which manipulates the GUI is called directly from your worker thread and remember this is prohibited! Since your worker is not the one calling QApplication::exec. To override the automatics and convince to correctly do the thread switch when calling the slot you must use Qt::QueuedConnection when doing the connect.

connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)), Qt::QueuedConnection);
David Feurle
  • 2,687
  • 22
  • 38