Use QNetworkAccessManager from multiple threads



  • 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.


  • Qt Champions 2016

    @RudolfVonKrugstein
    The problem is that QNetworkAccessManager::get is creating an object - QNetworkReply with a parent QNetworkAccessManager. This is not allowed because your networkManagerobject 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.


  • Lifetime Qt Champion

    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 ?



  • @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.


  • Lifetime Qt Champion

    There's something not quiet clear with your description.
    You want to:

    1. Use thread to make synchronous network request
    2. 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 ?



  • Yes, I that is correct


  • Lifetime Qt Champion

    Doesn't that defeat the purpose of the thread ?



  • @SGaist what exactly to you mean? What does defeat the purpose of the thread?


  • Lifetime Qt Champion

    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.



  • 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 ...).


  • Lifetime Qt Champion

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.