Gio
Gio

Reputation: 3340

Handling http-post (QnetworkAccessManager::post) responses inside QThread

I'm trying to handle http-post responses in a Qt worker thread. I've tried to do this the general recommended way, i.e. I create a thread as follows:

_thread = new QThread;
_worker = new Worker(this);
_worker->moveToThread(_thread);
// start the worker thread
connect(_thread, SIGNAL(started()), _worker, SLOT(process()));

And then in function process I do the following:

do {
    QNetworkAccesManger netw;
    // init req (headers) and payload
    //....
    QNetworkReply *reply = newt.post(req, payload);
    connect(reply, SIGNAL(readyRead()), SLOT(onReadyRead()), Qt::DirectConnection);
    connect(reply, SIGNAL(finished()), SLOT(onFinished()), Qt::DirectConnection);
    QThread::msleep(200);
} while (!terminate);

onReadyRead and onFinished are slots in the worker object. Problem is that onReadyRead or onFinished are never called. I believe this is because I'm not handling the events in the while loop.

I've tried a similar approach, where instead of using moveToThread I directly subclass QThread, in that way everything works as expected. I assume this is because QThread::run calls to exec() in order to handle events.

However I believe subclassing QThread is not the recommended way, can anybody explain what I'm missing here??

Upvotes: 0

Views: 328

Answers (1)

Mike
Mike

Reputation: 8355

I believe this is because I'm not handling the events in the while loop.

You are right, this is because you never handle events in your thread. But, you are wrong that you should be doing this in your while loop.

Let's examine what is happening here. Normally, when the QThread is started, run() function is called in the new thread which (if it has not been overridden) calls exec(). The exec() function provides an event loop for the thread, this is where the thread should be processing events.

In your code, started() is emitted (Note that this happens even before the run() function is called), this causes Worker::process() function to be called. And since your process() implementation never returns (unless when the thread is required to terminate), your thread never gets into the event loop to process events (as it is always executing the do-while loop in your process implementation) and QNetworkAccessManager can not tell it about the new signals it has.

Conclusion:

You should never have a function that never returns in an event-driven system. You should always return from your functions as soon as possible, so that the event loop can process pending events.

If you mean to execute the code in the do-while loop every 200 msecs, You should use a QTimer, connect its timeout() signal to the slot that should be executed every 200 msecs, then start() it with an interval of 200 msecs.

So, Here is how your code may look like:

_thread = new QThread;
_worker = new Worker(this);
_worker->moveToThread(_thread);
// start the worker thread
//calling init instead of process
//init will be responsible to schedule calls to "process" every 200 msecs
connect(_thread, SIGNAL(started()), _worker, SLOT(init()));

the init function should look something like this:

QTimer* timer= new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(process()));
//call "process" slot every 200 msecs
timer->start(200);
//call "process" the first time
process();

the process slot is much simpler now:

QNetworkAccesManger netw;
// init req (headers) and payload
//....
QNetworkReply *reply = newt.post(req, payload);
connect(reply, SIGNAL(readyRead()), SLOT(onReadyRead()), Qt::DirectConnection);
connect(reply, SIGNAL(finished()), SLOT(onFinished()), Qt::DirectConnection);

Upvotes: 2

Related Questions