Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Why QNetworkAccessManager::finished is fired on the main thread?



  • I created a QThread with a code like this:

    void MyThread::run()
    {
        QEventLoop loop;
    
        QNetworkAccessManager nm;
    
        QObject::connect(&nm, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply)
        {
             //the lambda is called on the main thread
        }
    
        QNetworkRequest request;
        request.setUrl(QUrl("https://api.binance.com/api/v3/exchangeInfo"));
        nm.get(request);
        
        loop.exec();
    }
    

    and expected that the lambda is called on the thread nm object belongs to, but it is called on the main thread. why?


  • Moderators

    @Dmitriano said in Why QNetworkAccessManager::finished is fired on the main thread?:

    and expected that the lambda is called on the thread nm object belongs to, but it is called on the main thread. why?

    Because this rule applies to all QObjects: A slot will execute in the thread that the QObject lives in. (See https://doc.qt.io/qt-5/qobject.html#thread-affinity )

    A QThread is a QObject that manages a secondary thread. However, your QThread object lives in the main thread. Therefore, its slots will execute in the main thread.

    QObject::connect(&nm, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply)
    {
        // This lambda runs in this->thread()
    }
    
    QObject::connect(&nm, &QNetworkAccessManager::finished, &nm, [=](QNetworkReply *reply)
    {
        // This lambda runs in nm.thread()
    }
    
    // To see which thread each object lives in, run this code:
    qDebug() << qApp->thread();
    qDebug() << this->thread();
    qDebug() << this;
    qDebug() << nm.thread();
    

    Note:

    • You don't need QEventLoop. Just call this->exec()
    • You don't even need a thread. QNetworkAccessManager is asynchronous -- you can run it in your main thread.

  • Lifetime Qt Champion

    Hi,

    How are you using your MyThread class ?



  • @SGaist I declare my thread class

        class MyThread : public QThread
        {
            Q_OBJECT;
    
        protected:
    
            void run() override;
        };
    

    then I declare its instance as a member of MyModel class derived from QAbstractListModel that is created in QML.

    in MyModel's constructor I call

    m_myThread.start();
    

    and when the app closes I call

    m_myThread.quit();
    m_myThread.wait();
    

  • Lifetime Qt Champion

    How did you determine that the lambda was called in the main thread ?



  • @SGaist I was able to debug my app, see the picture
    alt text


  • Moderators

    @Dmitriano said in Why QNetworkAccessManager::finished is fired on the main thread?:

    and expected that the lambda is called on the thread nm object belongs to, but it is called on the main thread. why?

    Because this rule applies to all QObjects: A slot will execute in the thread that the QObject lives in. (See https://doc.qt.io/qt-5/qobject.html#thread-affinity )

    A QThread is a QObject that manages a secondary thread. However, your QThread object lives in the main thread. Therefore, its slots will execute in the main thread.

    QObject::connect(&nm, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply)
    {
        // This lambda runs in this->thread()
    }
    
    QObject::connect(&nm, &QNetworkAccessManager::finished, &nm, [=](QNetworkReply *reply)
    {
        // This lambda runs in nm.thread()
    }
    
    // To see which thread each object lives in, run this code:
    qDebug() << qApp->thread();
    qDebug() << this->thread();
    qDebug() << this;
    qDebug() << nm.thread();
    

    Note:

    • You don't need QEventLoop. Just call this->exec()
    • You don't even need a thread. QNetworkAccessManager is asynchronous -- you can run it in your main thread.

  • Lifetime Qt Champion

    One more note:

    • Again a nice example on how to misuse lambdas

Log in to reply