Use QNetworkAccessManager from multiple threads
-
wrote on 5 Dec 2015, 15:49 last edited by
Running this code:
QCoreApplication a(argc, argv); QNetworkAccessManager* networkManager = new QNetworkAccessManager(); QtConcurrent::run([networkManager]() { networkManager->get(QNetworkRequest(QUrl("http://qt-project.org"))); }); QEventLoop loop; connect(reply,&QNetworkReply::finished,&loop,&QEventLoop::quit); loop.exec();
causes this warning/error:
QObject: Cannot create children for a parent that is in a different thread. (Parent is QNetworkAccessManager(0x1ab1d70), parent's thread is QThread(0x1a98fe0), current thread is QThread(0x1ab5db0)
So what should I do? Create a new QNetworkAccessManager every time?
Background: I like blocking network requests run in a thread because I think it makes the code more readable.
-
@RudolfVonKrugstein
The problem is that QNetworkAccessManager::get is creating an object - QNetworkReply with a parent QNetworkAccessManager. This is not allowed because yournetworkManager
object lives in another thread. Unfortunately, I don't know how to work around that problem in the high-level threading API, hopefully someone else will pitch in and suggest something.Kind regards.
-
Hi,
Like @kshegunov wrote, you can't do that the way you are currently doing it. If you really want to move everything in another thread, you should use the worker object approach.
However, first thing to analyze, why do you need that blocking behavior rather than the asynchronous ?
-
wrote on 5 Dec 2015, 22:21 last edited by
@SGaist: Well, the background is how I want to structure my code.
I want to write:
QtConcurrent::run([=](){ prepareRequest(); doRequest(); workWithResult(); });
arguably, one could also write:
prepareRequest(); QNetworkResult* res = doRequest(); connect(res,&QNetworkResult::finished,[=](){ workWithResult(); });
But then I want to have a function, which does the network request somewhere deep inside it and return something based on the result of the request. I could pass a callback parameter to this function, that would work, but I find this tedious when the structures get deeper.
Did my intention become clear? I am open to alternatives.
-
There's something not quiet clear with your description.
You want to:- Use thread to make synchronous network request
- Have a function that calls the request method of that thread and return the result of the processing of the reply.
Do I get you right ?
-
wrote on 6 Dec 2015, 01:12 last edited by
Yes, I that is correct
-
Doesn't that defeat the purpose of the thread ?
-
wrote on 7 Dec 2015, 00:08 last edited by
@SGaist what exactly to you mean? What does defeat the purpose of the thread?
-
Unless I misunderstood you, you are making an asynchronous function synchronous, move that logic to another thread so it doesn't block your GUI, then call a function on that thread that will block until it gets the answer. Is that correct ? If so, I don't see the advantage of the thread at all.
-
wrote on 8 Dec 2015, 12:36 last edited by
Well the point is, that I want to have multiple network operations (not just one) chained together and with logic between them.
I believe that with blocking operations the code is much more readable. Here is a pseudo code example:
QString getRandomWebsite() { int randomNumber = extractNumber(blockingRequest("http://random-number-site.org/2"); switch (randomNumber) { case 1: return blockingRequest("http://website1.org"); case 2: return blockingRequest("http://website1.org"); } } int countRandomWordInRandomWebsite() { QString website = getRandomWebsite(); QString randomWord = blockingRequest("http://random-number-site.org/random_word"); emit requestResult(website.count(randomWord)); }
If I would implement this using asynchronous calls, I believe it looses it readability (but I might not have thought yet of the ideal solution ...).
-
QNetworkAccessManager handles up to 6 network operations in parallel.
You can use lambdas to make the code more compact and understandable.
Watch out, you don't return anything in countRandomWordInRandomWebsite. You should have a compiler warning about that.
1/11