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. Calling disconnect frequently causes CPU usage to gradually rise on Qt 5.9.7 in Linux

Calling disconnect frequently causes CPU usage to gradually rise on Qt 5.9.7 in Linux

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 689 Views
  • 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.
  • V Offline
    V Offline
    Vivian-Scott
    wrote on last edited by Vivian-Scott
    #1

    The code in question handles sending data updates, so the signal slot connection is established, used, and then disconnected frequently (approximately twice a second). The connection needs to connect to relevant recipients only and then be disconnected so that the next update can be received only by parts of the application to which the update is relevant. Running this way, the CPU usage will steadily grow until it reaches 100% and crashes. Using perf to profile the datastore thread shows that the overhead is largely due to the QMetaObjectPrivate::disconnectHelper and QMetaObjectPrivate::activate. looking at the source code I don't see anything which could be causing the issue. Does anyone have any insights on what might be the reason for this behavior?

    1 Reply Last reply
    0
    • C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #2

      Without seeing your code we cannot say why CPU is going through the roof.

      From your description we can say that the design needs to be revisited. If you have a list of recipient objects to connect to when you have something to send then you can just call the receiving method directly (or place the data in a queue as appropriate) in simple loop rather than abusing the signal-slot mechanism.

      1 Reply Last reply
      0
      • V Offline
        V Offline
        Vivian-Scott
        wrote on last edited by
        #3

        Thank you for the quick response! The goal is to receive data over Ethernet on a network thread, then share that data with a variety of QObjects on different threads, so I figured signal-slot would be a good fit for this. The code in question looks something like this:

        for (object in targets) {
            connect(this, SIGNAL(signalDataUpdated(...), dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
        }
        emit signalDataUpdated(...);
        for (object in targets) {
            disconnect(dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
        }
        

        I could probably rewrite this as a queue, with separate routines in each thread that periodically check for data in the queue, but signal-slots seemed to greatly simplify the architecture if I can get around this CPU usage issue with the disconnectHandler. I also forgot to mention that this came after a codebase upgrade to Qt5 from Qt4, so I'm assuming some change in the signal-slot implementation exposed a flaw in what I was doing here. And if you can point me to what I'm abusing in the signal-slot functionality, that would help me wrap my mind around how to properly use signal-slots in the future.

        J.HilkJ 1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by SGaist
          #4

          Hi,

          I agree with @ChrisW67, your design is flawed.

          If not all objects shall receive these messages you should rather do something like MQTT where your objects subscribe to the messages they interested in and then you dispatch upon reception. Or depending on your implementation use something like MQTT or ZMQ, etc.

          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
          • V Offline
            V Offline
            Vivian-Scott
            wrote on last edited by
            #5

            In principle that is exactly how my code is designed: A QObject "subscribes" by adding itself to a list of QObjects that need data, paired with the types of messages they are designed to respond to. A message comes in on the network, and then its type is determined and used to filter which QObjects are subscribed to it. To be clear, I'm not really asking a networking question, I'm just trying to send data from one thread to QObjects that may be on multiple other threads.

            I can think of other solutions, like the queue I mentioned, or just emitting to every possible slot and doing the filtering in each slot, but what I really want to know is what specifically am I doing wrong by using signal-slots here, particularly that would cause the disconnectHandler to be so CPU intensive? For example, are signal-slots not intended to be connected and disconnected so often? Are they not intended to be attached to some QObjects and then reattached to others later? Understanding my misuse would greatly help me when deciding when to use signal-slots elsewhere as well. Thanks again for helping with this.

            1 Reply Last reply
            0
            • C Offline
              C Offline
              ChrisW67
              wrote on last edited by
              #6

              Signal-slot connections are typically created once, usually in a constructor, and persist for the life of the objects. I would say disconnecting on-the-fly is unusual, but it may happen in a UI that is dynamically adjusted (add/remove handfuls of widgets). Doing it en masse and frequently is certainly not typical.

              Looking at your code:

              for (object in targets) {
                  connect(this, SIGNAL(signalDataUpdated(...), dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
                  // in order to connect to object it must already be a QObject subclass.  
                  // The dynamic_cast should be unnecessary, and is generally considered fairly slow
              }
              emit signalDataUpdated(...);
              for (object in targets) {
                  disconnect(dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
                  // ditto
              }
              

              I am not sure what gyrations Qt needs to do with disconnections cross-thread, but I expect that these are slower than direct connections.

              1 Reply Last reply
              0
              • V Vivian-Scott

                Thank you for the quick response! The goal is to receive data over Ethernet on a network thread, then share that data with a variety of QObjects on different threads, so I figured signal-slot would be a good fit for this. The code in question looks something like this:

                for (object in targets) {
                    connect(this, SIGNAL(signalDataUpdated(...), dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
                }
                emit signalDataUpdated(...);
                for (object in targets) {
                    disconnect(dynamic_cast<QObject*>(object), SLOT(slotDataUpdated(...));
                }
                

                I could probably rewrite this as a queue, with separate routines in each thread that periodically check for data in the queue, but signal-slots seemed to greatly simplify the architecture if I can get around this CPU usage issue with the disconnectHandler. I also forgot to mention that this came after a codebase upgrade to Qt5 from Qt4, so I'm assuming some change in the signal-slot implementation exposed a flaw in what I was doing here. And if you can point me to what I'm abusing in the signal-slot functionality, that would help me wrap my mind around how to properly use signal-slots in the future.

                J.HilkJ Online
                J.HilkJ Online
                J.Hilk
                Moderators
                wrote on last edited by
                #7

                @Vivian-Scott this is the last solution I would have chosen for this situation :D

                Have you tried/considered invoking the slot directly, without the connect clutch?

                for (object in targets) {
                   QMetaObject::invokeMethod(object_cast<QObject*>(object), "slotDataUpdated");
                }
                

                or, since your slots seems to take an argument:

                for (object in targets) {
                   QMetaObject::invokeMethod(object_cast<QObject*>(object), "slotDataUpdated", Q_ARG(Type, value));
                }
                

                https://doc.qt.io/qt-6/qmetaobject.html#invokeMethod


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                1 Reply Last reply
                4
                • V Offline
                  V Offline
                  Vivian-Scott
                  wrote on last edited by
                  #8

                  Wow, I never knew about this function. This sounds perfect, thanks! Still unsure about what causes the disconnect to be so heavy in my previous implementation, but after a quick test here it looks like invokeMethod works perfectly, and is a lot cleaner too. Thanks for the help!

                  1 Reply Last reply
                  1

                  • Login

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