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. QNetworkAccessManager reusing connections -- breaks

QNetworkAccessManager reusing connections -- breaks

Scheduled Pinned Locked Moved Solved General and Desktop
18 Posts 7 Posters 2.2k Views 4 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.
  • C Offline
    C Offline
    ChrisW67
    wrote on last edited by
    #9

    We've all been there (or we are not trying hard enough).

    1 Reply Last reply
    1
    • C ChrisW67

      @poncho524

      HTTP Pipelining is the sending of multiple HTTP/1.1 requests on the same connection without waiting for their corresponding responses. Your code explicitly waits for a response and does not send a second request until the first is finished (so QNAM cannot be pipelining behind your back). I think pipelining is irrelevant to your problem. You can check for the attribute QNetworkRequest::HttpPipeliningWasUsedAttribute on the reply to confirm this.

      QNetworkAccessManager will reuse connections for multiple requests to the same server/port or use multiple connections to the same server to process queued requests. Once again, you serialise requests, so the queue is at most one long and parallel execution is also a non-issue.

      Your real issue is that you delete the wrong reply here:

      void HttpClient::processFirstDone()
      {
        emit httpClientReady();
        m_reply->deleteLater();
      }
      

      The slot called when you emit that signal is executed immediately and overwrites m_reply. When the signal returns you then queue deletion of the new reply. Swap the two lines and things will probably improve.

      JonBJ Online
      JonBJ Online
      JonB
      wrote on last edited by
      #10

      @ChrisW67 said in QNetworkAccessManager reusing connections -- breaks:

      Your real issue is that you delete the wrong reply here:
      void HttpClient::processFirstDone()
      {
      emit httpClientReady();
      m_reply->deleteLater();
      }

      The slot called when you emit that signal is executed immediately and overwrites m_reply. When the signal returns you then queue deletion of the new reply. Swap the two lines and things will probably improve.

      Hi Chris, this is a question for you, as you know more than I.

      It worries me when you say to put the deleteLater() first. The reply must remain valid till this slot exits and returns, right? And the delete will happen as soon as the main event loop gets a chance to do so. How do you know what emitting the httpClientReady signal might cause to happen in the outside world? It could cause the main loop to be reached and the delete to happen, yes or no?

      So.... would the following pattern be "safer"?

      void HttpClient::processFirstDone()
      {
        QNetworkReply *oldReply = m_reply;
        emit httpClientReady();
        oldReply->deleteLater();
      }
      
      JKSHJ 1 Reply Last reply
      0
      • JonBJ JonB

        @ChrisW67 said in QNetworkAccessManager reusing connections -- breaks:

        Your real issue is that you delete the wrong reply here:
        void HttpClient::processFirstDone()
        {
        emit httpClientReady();
        m_reply->deleteLater();
        }

        The slot called when you emit that signal is executed immediately and overwrites m_reply. When the signal returns you then queue deletion of the new reply. Swap the two lines and things will probably improve.

        Hi Chris, this is a question for you, as you know more than I.

        It worries me when you say to put the deleteLater() first. The reply must remain valid till this slot exits and returns, right? And the delete will happen as soon as the main event loop gets a chance to do so. How do you know what emitting the httpClientReady signal might cause to happen in the outside world? It could cause the main loop to be reached and the delete to happen, yes or no?

        So.... would the following pattern be "safer"?

        void HttpClient::processFirstDone()
        {
          QNetworkReply *oldReply = m_reply;
          emit httpClientReady();
          oldReply->deleteLater();
        }
        
        JKSHJ Offline
        JKSHJ Offline
        JKSH
        Moderators
        wrote on last edited by
        #11

        @JonB said in QNetworkAccessManager reusing connections -- breaks:

        The reply must remain valid till this slot exits and returns, right?

        Right.

        And the delete will happen as soon as the main event loop gets a chance to do so.

        I'm pretty sure the delete will happen after the main event loop finishes processing everything else in the event queue, not "as soon as it gets a chance".

        It could cause the main loop to be reached and the delete to happen, yes or no?

        No. After the event loop passed control to HttpClient::processFirstDone(), it cannot receive control again until HttpClient::processFirstDone() returns.

        If emit httpClientReady() has a Qt::DirectConnection, the connected slot will be called from inside HttpClient::processFirstDone() (so the event loop is not involved). If emit httpClientReady() has a Qt::QueuedConnection, the connected slot can't run until after HttpClient::processFirstDone() returns.

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

        JonBJ 1 Reply Last reply
        1
        • JKSHJ JKSH

          @JonB said in QNetworkAccessManager reusing connections -- breaks:

          The reply must remain valid till this slot exits and returns, right?

          Right.

          And the delete will happen as soon as the main event loop gets a chance to do so.

          I'm pretty sure the delete will happen after the main event loop finishes processing everything else in the event queue, not "as soon as it gets a chance".

          It could cause the main loop to be reached and the delete to happen, yes or no?

          No. After the event loop passed control to HttpClient::processFirstDone(), it cannot receive control again until HttpClient::processFirstDone() returns.

          If emit httpClientReady() has a Qt::DirectConnection, the connected slot will be called from inside HttpClient::processFirstDone() (so the event loop is not involved). If emit httpClientReady() has a Qt::QueuedConnection, the connected slot can't run until after HttpClient::processFirstDone() returns.

          JonBJ Online
          JonBJ Online
          JonB
          wrote on last edited by JonB
          #12

          @JKSH
          The question is what could happen if a programmer puts a QApplication::ProcessEvents() in whatever this slot calls (whatever emitting httpClientReady() causes)? And we know how many users like to call this, with or without a local QEventLoop....

          Now, it may be that this comes down to https://doc.qt.io/qt-5/qcoreapplication.html#processEvents and what it says about DeferredDelete events, which I believe is what deleteLater() calls/uses?

          In the event that you are running a local loop which calls this function continuously, without an event loop, the DeferredDelete events will not be processed. This can affect the behaviour of widgets, e.g. QToolTip, that rely on DeferredDelete events to function properly. An alternative would be to call sendPostedEvents() from within that local loop.

          So, please, I invite you to comment, because this is an area I have been unsure about. Are you saying Qt is saying that even with some QApplication::processEvents() somewhere Qt will not act on a pending deleteLater()? That is my area of concern.

          1 Reply Last reply
          0
          • Christian EhrlicherC Online
            Christian EhrlicherC Online
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #13

            QCoreApplication::processEvents() does not run the event loop, it just processes events so QObject::deleteLater() will not be called in there ('The object will be deleted when control returns to the event loop.') :)
            Technically deleteLater is also only an event but it's handled specially like this comment in qcoreapplication.cpp show us:

            // Events sent by non-Qt event handlers (such as glib) may not
            // have the scopeLevel set correctly. The scope level makes sure that
            // code like this:
            //     foo->deleteLater();
            //     qApp->processEvents(); // without passing QEvent::DeferredDelete
            // will not cause "foo" to be deleted before returning to the event loop.
            

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            JonBJ 1 Reply Last reply
            4
            • Christian EhrlicherC Christian Ehrlicher

              QCoreApplication::processEvents() does not run the event loop, it just processes events so QObject::deleteLater() will not be called in there ('The object will be deleted when control returns to the event loop.') :)
              Technically deleteLater is also only an event but it's handled specially like this comment in qcoreapplication.cpp show us:

              // Events sent by non-Qt event handlers (such as glib) may not
              // have the scopeLevel set correctly. The scope level makes sure that
              // code like this:
              //     foo->deleteLater();
              //     qApp->processEvents(); // without passing QEvent::DeferredDelete
              // will not cause "foo" to be deleted before returning to the event loop.
              
              JonBJ Online
              JonBJ Online
              JonB
              wrote on last edited by
              #14

              @Christian-Ehrlicher
              Thank you, helpful. So to be clear:

              control returns to the event loop

              • There is just one, unique main Qt event loop running? (Or maybe more precisely one per thread?)
              • User cannot write code that, from a slot/anywhere, itself can enter that loop?
              1 Reply Last reply
              0
              • Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #15

                @JonB said in QNetworkAccessManager reusing connections -- breaks:

                User cannot write code that, from a slot/anywhere, itself can enter that loop?

                more or less - calling QCoreApplication::processEvent() executes the loop, but with a higher scopeLevel counter I would guess.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                JonBJ 1 Reply Last reply
                1
                • Christian EhrlicherC Christian Ehrlicher

                  @JonB said in QNetworkAccessManager reusing connections -- breaks:

                  User cannot write code that, from a slot/anywhere, itself can enter that loop?

                  more or less - calling QCoreApplication::processEvent() executes the loop, but with a higher scopeLevel counter I would guess.

                  JonBJ Online
                  JonBJ Online
                  JonB
                  wrote on last edited by
                  #16

                  @Christian-Ehrlicher said in QNetworkAccessManager reusing connections -- breaks:

                  higher scopeLevel counter

                  OK that makes sense, is your wording "conceptual" or does Qt code pass some actual counter around to indicate a level?

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Online
                    Christian EhrlicherC Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #17

                    @JonB said in QNetworkAccessManager reusing connections -- breaks:

                    or does Qt code pass some actual counter around to indicate a level?

                    There is a counter: https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp.html#1574

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    JonBJ 1 Reply Last reply
                    2
                    • Christian EhrlicherC Christian Ehrlicher

                      @JonB said in QNetworkAccessManager reusing connections -- breaks:

                      or does Qt code pass some actual counter around to indicate a level?

                      There is a counter: https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp.html#1574

                      JonBJ Online
                      JonBJ Online
                      JonB
                      wrote on last edited by
                      #18

                      @Christian-Ehrlicher Perfect, in context that code & comments all makes sense to me now.

                      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