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. How to postpone function call as event in the loop?
Forum Updated to NodeBB v4.3 + New Features

How to postpone function call as event in the loop?

Scheduled Pinned Locked Moved General and Desktop
11 Posts 5 Posters 8.6k 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.
  • A Offline
    A Offline
    Adam Badura
    wrote on last edited by
    #1

    I have an UDPListener object (derived from QObject) that is run on a dedicated background QThread. It joins a multicast group and keeps reading and propagating datagrams.

    UDPListener::run slot (invoked in respons to QThread::started signal) connects to QUdpSocket::readyRead signal (a function "processDatagrams" which keeps reading datagrams as long as there are any and the returns). Then UDPListener reads all already pending datagrams (since readyRead will not be emitted if there are already pending datagrams) with the very same "processDatagrams" and in the end returns. Now the thread runs its loop and whenever readyRead is emitted UDPListener will again read all pending datagrams and return.

    This works fine (at least it seems so).

    But if I'm not mistaken (correct me if I'm!) if datagrams keep coming fast enough I will keep reading them in the "processDatagrams" function and never return control to the events loop. It might be better to read one datagram at a time and return to events loop. But how would next datagram be read if readyRead will not be emitted in such cases?

    So I thought that after reading a datagram I could check if there are any other datagrams and if so then somehow post to the events loop a second invocation of the read method and just return. If there would be no more datagrams then I could just return since if new datagram appears readyRead will be emitted.

    Is it proper approach? How to post (postpone in fact) such method invocation?

    1 Reply Last reply
    0
    • A Offline
      A Offline
      akonradwesolutions
      wrote on last edited by
      #2

      Create a slot or mark your method mit Q_INVOKABLE and use QMetaObject::invokeMethod:

      @
      // ...
      public:
      Q_INVOKABLE processDatagrams();
      //...
      @
      @
      //...
      QMetaObject::invokeMethod(obj, "processDatagrams", Qt::QueuedConnection);
      @

      This a method invocation event that is process through the event loop.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        mcosta
        wrote on last edited by
        #3

        [quote author="Adam Badura" date="1364377694"]Then UDPListener reads all already pending datagrams (since readyRead will not be emitted if there are already pending datagrams) with the very same "processDatagrams" and in the end returns. [/quote]

        Reading "readyRead":http://qt-project.org/doc/qt-5.0/qtcore/qiodevice.html#readyRead docs you see that is emitted each time a new datagram comes

        Once your problem is solved don't forget to:

        • Mark the thread as SOLVED using the Topic Tool menu
        • Vote up the answer(s) that helped you to solve the issue

        You can embed images using (http://imgur.com/) or (http://postimage.org/)

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Adam Badura
          wrote on last edited by
          #4

          How doing slot alone will help? Or do you mean that a slot by itself (without adding Q_INVOKABLE) allows incokeMethod?

          As to the invokeMethod is it the only way? Looks bad for me. Passing a string is problematic since it requires me to update it if I change the name since compiler will not see error there. Also it suggests that there will be a string-based look-up for the proper entry.

          Is there any other way or is it the only one?

          1 Reply Last reply
          0
          • A Offline
            A Offline
            Adam Badura
            wrote on last edited by
            #5

            [quote author="mcosta" date="1364378405"]
            Reading "readyRead":http://qt-project.org/doc/qt-5.0/qtcore/qiodevice.html#readyRead docs you see that is emitted each time a new datagram comes [/quote]

            "QUdpSocket":http://qt-project.org/doc/qt-5.0/qtnetwork/qudpsocket.html documentation says differently:

            bq. Note: An incoming datagram should be read when you receive the readyRead() signal, otherwise this signal will not be emitted for the next datagram.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              andre
              wrote on last edited by
              #6

              A slot is invokable, but not the other way around. You can also just use a signal/slot connection that you also connect as queued. Or, you push your data into a queue, and use a timer to process that queue.

              1 Reply Last reply
              0
              • M Offline
                M Offline
                mcosta
                wrote on last edited by
                #7

                If you aren't sure your read rate isn't enought fast you could limit the number of datagrams to deque in single slot and use a timer and periodically check if there are pending datagrams to process.

                However, if the producer (process that sends datagrams) is always faster than consumer (your process), you have a problem and you should consider to change your architecture.

                Once your problem is solved don't forget to:

                • Mark the thread as SOLVED using the Topic Tool menu
                • Vote up the answer(s) that helped you to solve the issue

                You can embed images using (http://imgur.com/) or (http://postimage.org/)

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Adam Badura
                  wrote on last edited by
                  #8

                  I just tried a version in which:

                  UDPListener in its "run" method (slot for QThread::started signal) connects "processDatagram" slot to QUdpSocket::readyRead and the calls "processDatagram" explicitly if there is any datagram pending (QUdpSocket::hasPendingDatagrams).

                  "processDatagram" reads and processes the datagram (by emitting another signal) and then if there is any pending datagram it calls the QMetaObject::invokeMethod for itself (as described above).

                  So essentially where I previously had a while loop (on QUdpSocket::hasPendingDatagrams) that called "processDatagram" no I have an if (on QUdpSocket::hasPendingDatagrams as well) that calls "processDatagram" by invokeMethod.

                  But when I run the application it was nearly non-responsive. I'm not sure why. I checked few times by interrupting and most commonly it stopped in the worker thread processEvent (some Qt internal function). Sometimes in main thread in the slot called from the thread.

                  I have to investigate it more.

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    mcosta
                    wrote on last edited by
                    #9

                    Hi,

                    are you sure you can't manage receiving only with readyRead signal and looping in slot?
                    Have you make some tests about your receiving rate?

                    You can try with

                    in "processDatagram" fix the maximum number of datagram to read

                    use a Timer and connect "timeout()" signal with "processDatagram"

                    In this way processDatagram is called upon receiving readyRead signal and periodically

                    Once your problem is solved don't forget to:

                    • Mark the thread as SOLVED using the Topic Tool menu
                    • Vote up the answer(s) that helped you to solve the issue

                    You can embed images using (http://imgur.com/) or (http://postimage.org/)

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Hi,

                      If you can, share the code with us, so we might be able to see more clearly what is happening.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        Adam Badura
                        wrote on last edited by
                        #11

                        I posted the code in "a different thread":http://qt-project.org/forums/viewthread/26145/#119544 (a different issue with same code). Please have a look there.

                        Firstly I shall note that I don't know if that is needed at all. I guess it is not. At least initial tests show that the loop-based code is just fine. But since I'm also learning Qt and exploring it I considered this issue and means to work around it.

                        So what I don't like in that code is the UDPListener::processDatagrams function. It contains a loop that could (theoretically) "hang" the thread in which UDPListener runs (NetworkWatcher::theUDPListenerThreadPtr) by never returning to processing events. This could be also an issue when you try to quit the thread.

                        So I changed (along your suggestions) the code by replacing the loop with a condition, so now it is:
                        @void processDatagrams()
                        {
                        if ( theSocketPtr->hasPendingDatagrams() )
                        QMetaObject::invokeMethod( this, "processDatagram", Qt::QueuedConnection );
                        }@

                        (I do know it could be simplified a bit but I don't think that is matters here much.)

                        The observation is that after that change the application (main thread!) drops in responsiveness dramatically. Why is that?

                        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