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?
-
@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.
- You don't need QEventLoop. Just call
-
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();
-
How did you determine that the lambda was called in the main thread ?
-
@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.
- You don't need QEventLoop. Just call
-
One more note:
- Again a nice example on how to misuse lambdas