PDA

View Full Version : QNetworkAccessManager and QRunnable issue



luk_man_
22nd October 2019, 14:34
Hello,

I have the such code architecture. For each request I am creating Worker class, which is QRunnable object and it should be started in a new QThread by QThreadPool.
This Worker has the following code:



#include "Worker.h"
#include <QString>

Worker::Worker(const WorkerData& data) :
_reader()
_writer(),
_sender()
{
}

void Worker::run()
{
_reader.readFile();
}

void Worker::sendData(const DataToSend& data)
{
_writer.write(data);
_sender.send(data);
}


The Sender header code:

#include <QObject>
#include <QtNetwork/QNetworkAccessManager>

class DataSender : public QObject
{
Q_OBJECT
public:
DataSender();

void send(const DataToSend& data);

private:
QNetworkAccessManager _networkMgr;
};

The Sender.cpp code:

#include <QUrl>
#include <QJsonObject>
#include <QJsonDocument>
#include <QtNetwork/QNetworkReply>
DataSender::DataSender() : _networkMgr()
{

}

void DataSender::send(const DataToSend& data)
{
qDebug() << "\tINFO: [DataSender::send] sending data to endpoint: " << data;

QUrl serviceUrl = QUrl("http://someUrl.com");
QNetworkRequest request(serviceUrl);
QJsonObject json;
json.insert("data", data.first());
QJsonDocument jsonDoc(json);
QByteArray jsonData= jsonDoc.toJson();
request.setHeader(QNetworkRequest::ContentTypeHead er,"application/json");
request.setHeader(QNetworkRequest::ContentLengthHe ader,QByteArray::number(jsonData.size()));
QNetworkReply *reply = _networkMgr.post(request, jsonData);
}

As you know, the only run() method in QRunnable object is running in a new thread. Based on that, all my QNetworkAccessManager is created in the old thread, because it is not created in run method, am I right?

I am asking about that, because i got the following error:


QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xda5a74c), parent's thread is QThread(0xdb14e0), current thread is QThread(0xda579a0)

Do you have any idea why I get this error?
I do not see the cause of the problem...

ChristianEhrlicher
22nd October 2019, 16:05
Why do you want to create the request in a separate thread at all? It's not needed: https://doc.qt.io/qt-5/qnetworkaccessmanager.html#details

luk_man_
22nd October 2019, 16:34
Why do you want to create the request in a separate thread at all? It's not needed: https://doc.qt.io/qt-5/qnetworkaccessmanager.html#details

..because there will be a lot of requests to my main app and I would like to dispatch them to many threads, thus I use QThreadPool with Workers for each request.

ChristianEhrlicher
22nd October 2019, 17:09
So did you actually read the link? Then you would see that your idea will not work.

luk_man_
22nd October 2019, 17:28
So did you actually read the link? Then you would see that your idea will not work.

Yes, I saw it. Network manager must be run in the same thread it was created. Based on that I create it in worker, but Worker itself is not in the new thread. In the new thread is Worker::run() method only, am I right?

ChristianEhrlicher
22nd October 2019, 17:51
I meant this:

"Note: QNetworkAccessManager queues the requests it receives. The number of requests executed in parallel is dependent on the protocol. Currently, for the HTTP protocol on desktop platforms, 6 requests are executed in parallel for one host/port combination."

So there is no real need to create a thread and when then you need to create on QNAM per thread.

luk_man_
22nd October 2019, 23:15
I meant this:

"Note: QNetworkAccessManager queues the requests it receives. The number of requests executed in parallel is dependent on the protocol. Currently, for the HTTP protocol on desktop platforms, 6 requests are executed in parallel for one host/port combination."

So there is no real need to create a thread and when then you need to create on QNAM per thread.

I see, but presence of QNAM is not the main factor to using QThreadPool class. Each request processes files (read/write one file) and based on that the application architecture is better and more flexible.

d_stranz
23rd October 2019, 16:57
based on that the application architecture is better and more flexible.

I have a square peg. I do not care if the hole is round. I will make it fit. I just need to use a bigger hammer.

Maybe you should consider threading the file processing after the network requests are complete, and not combine the two and attempt to thread the whole thing.