Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] A problem about QNetworkAccessManager, QThread and Event Loop
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] A problem about QNetworkAccessManager, QThread and Event Loop

Scheduled Pinned Locked Moved General and Desktop
5 Posts 3 Posters 4.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • sheeleyS Offline
    sheeleyS Offline
    sheeley
    wrote on last edited by sheeley
    #1

    Hi there.
    I have a problem about QNetworkAccessManager, QThread and Event Loop. I want to do a HTTP request periodically in a new thread. Since QNetworkAccessManager needs the event loop, I have to use QThread::exec() in the run() of the thread. But in this way, I cannot do the periodical request. Here are my codes:

    void DIThread::replyFinished(QNetworkReply *reply) {
      qDebug() << "Here";
      QTextCodec *codec = QTextCodec::codecForName("UTF-8");
      QString all = codec->toUnicode(reply->readAll());
      qDebug() << all;
      reply->deleteLater();
      sleep(1);
      manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));
    }
    
    void DIThread::run() {
      manager = new QNetworkAccessManager();
      connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
      manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));
      QThread::exec();
    }
    

    the function manager->get(QNetworkRequest(QUrl("http://www.baidu.com"))); will execute one time, and errors will appear in the next time:
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNetworkAccessManager(0x13d9c98), parent's thread is DIThread(0x12fb70), current thread is QThread(0x4aeab0)
    So, how to fix this problem?

    I like programming :)

    1 Reply Last reply
    0
    • jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Why do you call QThread::exec() in run()?
      Check the example in http://doc.qt.io/qt-5.5/qthread.html

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      sheeleyS 1 Reply Last reply
      0
      • jsulmJ jsulm

        Why do you call QThread::exec() in run()?
        Check the example in http://doc.qt.io/qt-5.5/qthread.html

        sheeleyS Offline
        sheeleyS Offline
        sheeley
        wrote on last edited by
        #3

        @jsulm Thanks for your reply.
        If don't call exec(), the slot will not work.

        I like programming :)

        1 Reply Last reply
        0
        • JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote on last edited by
          #4

          @sheeley said:

          connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

          This is the cause of your problem.

          See the documentation that @jsulm posted:

          It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

          When subclassing QThread, keep in mind that the constructor executes in the old thread while run() executes in the new thread.

          The problem is, run() is called in the new thread, but replyFinished() is called in the old thread.

          • run() constructs a QNetworkAccessManager in the new thread, and calls QNetworkAccessManager::get() in the new thread. This is OK.
          • replyFinished() calls QNetworkAccessManager::get() in the old thread. This is not allowed.

          Do not add a slot to DIThread. Use a lambda function to handle the signal:

          connect(manager, &QNetworkAccessManager::finished, [=](QNetworkReply *reply) {
              qDebug() << reply->readAll().toUtf8(); // You don't need QTextCodec!
              reply->deleteLater();
              sleep(1);
              manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));
          });
          

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          sheeleyS 1 Reply Last reply
          2
          • JKSHJ JKSH

            @sheeley said:

            connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

            This is the cause of your problem.

            See the documentation that @jsulm posted:

            It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

            When subclassing QThread, keep in mind that the constructor executes in the old thread while run() executes in the new thread.

            The problem is, run() is called in the new thread, but replyFinished() is called in the old thread.

            • run() constructs a QNetworkAccessManager in the new thread, and calls QNetworkAccessManager::get() in the new thread. This is OK.
            • replyFinished() calls QNetworkAccessManager::get() in the old thread. This is not allowed.

            Do not add a slot to DIThread. Use a lambda function to handle the signal:

            connect(manager, &QNetworkAccessManager::finished, [=](QNetworkReply *reply) {
                qDebug() << reply->readAll().toUtf8(); // You don't need QTextCodec!
                reply->deleteLater();
                sleep(1);
                manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));
            });
            
            sheeleyS Offline
            sheeleyS Offline
            sheeley
            wrote on last edited by
            #5

            @JKSH Thanks very much! It works! I'll check the documentation for more details. Thanks again.

            I like programming :)

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved