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. When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?
Forum Updated to NodeBB v4.3 + New Features

When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 4 Posters 4.6k Views 2 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.
  • stackprogramerS Offline
    stackprogramerS Offline
    stackprogramer
    wrote on last edited by
    #1

    When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?
    This means that if a signal was emitted before the disconnection, the corresponding slot may still be executed even after the disconnection.
    Can anyone guide me? Thanks in advance

    JonBJ B 2 Replies Last reply
    0
    • stackprogramerS stackprogramer

      When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?
      This means that if a signal was emitted before the disconnection, the corresponding slot may still be executed even after the disconnection.
      Can anyone guide me? Thanks in advance

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @stackprogramer said in When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?:

      How clear queued connection ?

      I don't think you can. Qt keeps it private.

      any queued connections that have already been made will still be delivered.
      This means that if a signal was emitted before the disconnection, the corresponding slot may still be executed even after the disconnection.

      Are you sure? I would be surprised if that were the case for queued connections. The signal is emitted and put in the event queue for later processing. When the event loop is next allowed to run it sees the signal and then looks up what slots are attached to call them. If a slot has been disconnected before that point I don't see where it would have stored the slot to call it other than where it has been disconnected from. Maybe if you disconnect in the middle of the dispatching it will still get called, but not if the disconnection has already happened?

      Can you produce a small, repeatable test demonstrating this behaviour?

      UPDATE
      Well, https://stackoverflow.com/questions/2532341/problem-with-qtqueuedconnection-signal-delivered-after-disconnect (from Qt 4.6) confirms what you are saying. It may seem "intuitive" to the responder there that

      When you do emit completed(), it makes sense for the signal to immediately activate or queue all connected slots

      but it does not seem "intuitive" to me!

      I suggest you Google qt disconnect queued as I did. You will find a few hits. None of them a simple resolutions, such as "clear the queue", but are worth reading for a choice of possible approaches. Don't forget: you might have the slot test a variable to see whether to exit immediately, and you set that at the same time as you disconnect so that the slot is still called but does nothing. Or similarly to avoid having to change the actual slot function code, have the connect go via an intermediate slot which does this testing work and calls the real slot if the flag is clear. Ugly, but so are the other proposals....

      1 Reply Last reply
      0
      • stackprogramerS stackprogramer

        When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?
        This means that if a signal was emitted before the disconnection, the corresponding slot may still be executed even after the disconnection.
        Can anyone guide me? Thanks in advance

        B Offline
        B Offline
        Bonnie
        wrote on last edited by
        #3

        @stackprogramer
        This is an interesting topic :)

        The closest approach I found is QCoreApplication::removePostedEvents(receiver, QEvent::MetaCall), since the queued connection is actually added to the event loop by QCoreApplication::postEvent.
        But this will clear all the queued connections of the receiver object, it doesn't care which slot.

        Also I found that if I disconnect the signal before the slot is called, the sender() in the slot returns 0.
        So if there isn't a perfect solution to clear the queue, maybe we could add something in the slot function like

        if(!sender())
            return;
        
        JonBJ stackprogramerS 2 Replies Last reply
        1
        • B Bonnie

          @stackprogramer
          This is an interesting topic :)

          The closest approach I found is QCoreApplication::removePostedEvents(receiver, QEvent::MetaCall), since the queued connection is actually added to the event loop by QCoreApplication::postEvent.
          But this will clear all the queued connections of the receiver object, it doesn't care which slot.

          Also I found that if I disconnect the signal before the slot is called, the sender() in the slot returns 0.
          So if there isn't a perfect solution to clear the queue, maybe we could add something in the slot function like

          if(!sender())
              return;
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @Bonnie said in When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?:

          Also I found that if I disconnect the signal before the slot is called, the sender() in the slot returns 0.

          Isn't this also the case if e.g. the slot is a lambda? Though I suppose in that case the OP would not be trying to remove the connection?

          B 1 Reply Last reply
          0
          • B Bonnie

            @stackprogramer
            This is an interesting topic :)

            The closest approach I found is QCoreApplication::removePostedEvents(receiver, QEvent::MetaCall), since the queued connection is actually added to the event loop by QCoreApplication::postEvent.
            But this will clear all the queued connections of the receiver object, it doesn't care which slot.

            Also I found that if I disconnect the signal before the slot is called, the sender() in the slot returns 0.
            So if there isn't a perfect solution to clear the queue, maybe we could add something in the slot function like

            if(!sender())
                return;
            
            stackprogramerS Offline
            stackprogramerS Offline
            stackprogramer
            wrote on last edited by
            #5

            @Bonnie Thanks after searching I concluded that we can not clear them (queued connections), but we can define some counters for signal and slot when signal and slot emit or executed counters in increased...
            when queued connections are finished that these counters be equal.

            if(counterSignal==counterSlot)
            {
            //We can conclude that queued connections are empty
            }
            

            But your offer @Bonnie is attractive for when we can detect queued connections are empty

            if(!sender())
                return;
            
            stackprogramerS 1 Reply Last reply
            0
            • stackprogramerS stackprogramer

              @Bonnie Thanks after searching I concluded that we can not clear them (queued connections), but we can define some counters for signal and slot when signal and slot emit or executed counters in increased...
              when queued connections are finished that these counters be equal.

              if(counterSignal==counterSlot)
              {
              //We can conclude that queued connections are empty
              }
              

              But your offer @Bonnie is attractive for when we can detect queued connections are empty

              if(!sender())
                  return;
              
              stackprogramerS Offline
              stackprogramerS Offline
              stackprogramer
              wrote on last edited by stackprogramer
              #6

              @Bonnie @JonB Thanks very much

              I also add when I used Qt::AutoConnection I was faced with queued connections problems. But when I used Qt::DirectConnection I had not this problem. I was faced with another problem GUI main thread is locked and all push-button clicking not working

              For more info see the below link
              https://doc.qt.io/qt-6/qt.html#ConnectionType-enum

              JonBJ 1 Reply Last reply
              0
              • JonBJ JonB

                @Bonnie said in When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?:

                Also I found that if I disconnect the signal before the slot is called, the sender() in the slot returns 0.

                Isn't this also the case if e.g. the slot is a lambda? Though I suppose in that case the OP would not be trying to remove the connection?

                B Offline
                B Offline
                Bonnie
                wrote on last edited by
                #7

                @JonB It is [sender() == 0] when you connect a lambda to a signal without a context Object, but in that case you cann't specify the connection type to be Qt::QueuedConnection, so I think it would't be queued.

                stackprogramerS 1 Reply Last reply
                0
                • stackprogramerS stackprogramer

                  @Bonnie @JonB Thanks very much

                  I also add when I used Qt::AutoConnection I was faced with queued connections problems. But when I used Qt::DirectConnection I had not this problem. I was faced with another problem GUI main thread is locked and all push-button clicking not working

                  For more info see the below link
                  https://doc.qt.io/qt-6/qt.html#ConnectionType-enum

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @stackprogramer said in When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?:

                  But when I used Qt::DirectConnection I had not this problem.

                  For direct connections there is no queue --- slots are called directly when the signal is emitted.

                  I was faced with another problem GUI main thread is locked and all push-button clicking not working

                  That depends what you are doing in any slot, or other code. The main GUI thread must be allowed to run at all times, if you block that or a slot takes a long time to execute you will see this kind of "freezing".

                  1 Reply Last reply
                  1
                  • B Bonnie

                    @JonB It is [sender() == 0] when you connect a lambda to a signal without a context Object, but in that case you cann't specify the connection type to be Qt::QueuedConnection, so I think it would't be queued.

                    stackprogramerS Offline
                    stackprogramerS Offline
                    stackprogramer
                    wrote on last edited by stackprogramer
                    #9

                    @JonB
                    Thanks very much yes it is not related to GUI main thread, I had a /dev/rtc0 in Linux kernel, and I used it in my application now we examine it, we concluded that We need to slow down the rtc interrupt, I changed the interrupt time from 1 ms to 60ms now everything is ok and GUI main thread works correctly.

                    More info:
                    https://forum.qt.io/topic/143484/when-i-used-rtc-on-different-thread-all-gui-qt-is-lock/10?_=1680082208135

                    1 Reply Last reply
                    0
                    • JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #10

                      @stackprogramer , @Bonnie
                      Just out of interest I knocked up the simplest example of a queued connection and disconnect:

                      #include <QDebug>
                      
                      #include "widget.h"
                      
                      Widget::Widget(QWidget *parent)
                          : QWidget(parent)
                      {
                          connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutDirect, Qt::DirectConnection);
                          connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued, Qt::QueuedConnection);
                          timer.start(1000);
                      }
                      
                      Widget::~Widget()
                      {
                      }
                      
                      void Widget::onTimeoutDirect()
                      {
                          static int counter = 1;
                          qDebug() << "onTimeoutDirect" << sender();
                          if (counter-- == 0)
                          {
                              qDebug() << "Disconnecting";
                              disconnect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued);
                              qDebug() << "Disconnected";
                          }
                      }
                      
                      void Widget::onTimeoutQueued()
                      {
                          qDebug() << "onTimeoutQueued" << sender();
                      }
                      

                      Under Ubuntu 22.04 and Qt 5.15.x the output is:

                      onTimeoutDirect QTimer(0x7fffffffe450)
                      onTimeoutQueued QTimer(0x7fffffffe450)
                      onTimeoutDirect QTimer(0x7fffffffe450)
                      Disconnecting
                      Disconnected
                      onTimeoutDirect QTimer(0x7fffffffe450)
                      onTimeoutDirect QTimer(0x7fffffffe450)
                      

                      This shows that after the disconnect() I do not get any further calls to the disconnected queued slot (onTimeoutQueued()).

                      What is the difference between my case and your findings?

                      My disconnect happens during the execution of the first, directly-connected slot. But so what? The explanation claims that "all connected slots are marked/queued for calling at emit time, not when the Qt event loop sees the previously-queued signal and starts to execute it". That should have caused a second onTimeoutQueued to have been output after Disconnected. I don't see how that explanation holds up here?

                      B 1 Reply Last reply
                      2
                      • JonBJ JonB

                        @stackprogramer , @Bonnie
                        Just out of interest I knocked up the simplest example of a queued connection and disconnect:

                        #include <QDebug>
                        
                        #include "widget.h"
                        
                        Widget::Widget(QWidget *parent)
                            : QWidget(parent)
                        {
                            connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutDirect, Qt::DirectConnection);
                            connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued, Qt::QueuedConnection);
                            timer.start(1000);
                        }
                        
                        Widget::~Widget()
                        {
                        }
                        
                        void Widget::onTimeoutDirect()
                        {
                            static int counter = 1;
                            qDebug() << "onTimeoutDirect" << sender();
                            if (counter-- == 0)
                            {
                                qDebug() << "Disconnecting";
                                disconnect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued);
                                qDebug() << "Disconnected";
                            }
                        }
                        
                        void Widget::onTimeoutQueued()
                        {
                            qDebug() << "onTimeoutQueued" << sender();
                        }
                        

                        Under Ubuntu 22.04 and Qt 5.15.x the output is:

                        onTimeoutDirect QTimer(0x7fffffffe450)
                        onTimeoutQueued QTimer(0x7fffffffe450)
                        onTimeoutDirect QTimer(0x7fffffffe450)
                        Disconnecting
                        Disconnected
                        onTimeoutDirect QTimer(0x7fffffffe450)
                        onTimeoutDirect QTimer(0x7fffffffe450)
                        

                        This shows that after the disconnect() I do not get any further calls to the disconnected queued slot (onTimeoutQueued()).

                        What is the difference between my case and your findings?

                        My disconnect happens during the execution of the first, directly-connected slot. But so what? The explanation claims that "all connected slots are marked/queued for calling at emit time, not when the Qt event loop sees the previously-queued signal and starts to execute it". That should have caused a second onTimeoutQueued to have been output after Disconnected. I don't see how that explanation holds up here?

                        B Offline
                        B Offline
                        Bonnie
                        wrote on last edited by
                        #11

                        Well, if I change you code to

                        connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued, Qt::QueuedConnection);
                        connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutDirect, Qt::DirectConnection);
                        

                        Then you'll see the difference

                        onTimeoutDirect QTimer(0x92815ff568)
                        onTimeoutQueued QTimer(0x92815ff568)
                        onTimeoutDirect QTimer(0x92815ff568)
                        Disconnecting
                        Disconnected
                        onTimeoutQueued QTimer(0x92815ff568)
                        onTimeoutDirect QTimer(0x92815ff568)
                        onTimeoutDirect QTimer(0x92815ff568)
                        

                        And it is even different from my previous finding, the sender() after disconnecting the queued slot is still not 0.
                        I guess there is something very special in this specific case :)

                        JonBJ 1 Reply Last reply
                        0
                        • B Bonnie

                          Well, if I change you code to

                          connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutQueued, Qt::QueuedConnection);
                          connect(&timer, &QTimer::timeout, this, &Widget::onTimeoutDirect, Qt::DirectConnection);
                          

                          Then you'll see the difference

                          onTimeoutDirect QTimer(0x92815ff568)
                          onTimeoutQueued QTimer(0x92815ff568)
                          onTimeoutDirect QTimer(0x92815ff568)
                          Disconnecting
                          Disconnected
                          onTimeoutQueued QTimer(0x92815ff568)
                          onTimeoutDirect QTimer(0x92815ff568)
                          onTimeoutDirect QTimer(0x92815ff568)
                          

                          And it is even different from my previous finding, the sender() after disconnecting the queued slot is still not 0.
                          I guess there is something very special in this specific case :)

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

                          @Bonnie said in When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?:

                          onTimeoutDirect QTimer(0x92815ff568)
                          Disconnecting
                          Disconnected
                          onTimeoutQueued QTimer(0x92815ff568)

                          Interesting!

                          My argument here however was with the explanation given in https://stackoverflow.com/a/2532586:

                          I think Qt is behaving in the most intuitive way.

                          When you do emit completed(), it makes sense for the signal to immediately activate or queue all connected slots.

                          There is only one emit of the timeout signal from the QTimer, though two slots are attached. Then I do not see how that would explain the difference in behaviour we have shown depending on the order of the slots/disconnection, if slot-calling is determined at the instant of the emit. Maybe I misunderstand what that person meant.

                          And it is even different from my previous finding, the sender() after disconnecting the queued slot is still not 0.

                          Indeed, so that may not be the way to go! :) Was your finding in the context of a separate thread using queued connection, maybe that behaviour differs?

                          1 Reply Last reply
                          0
                          • S Offline
                            S Offline
                            SimonSchroeder
                            wrote on last edited by
                            #13

                            I believe that queued connections are not delivered if the receiver is delete (not via deleteLater()!). This brings up the idea to have a SignalProxy class similar to QSignalMapper, but instead of mapping a signal you just forward it. Instead of using disconnect() you could then just delete your instance of SignalProxy. Your original signal could have the queued connection to the SignalProxy and the SignalProxy can have a direct connection to your original slot.

                            JonBJ 1 Reply Last reply
                            0
                            • S SimonSchroeder

                              I believe that queued connections are not delivered if the receiver is delete (not via deleteLater()!). This brings up the idea to have a SignalProxy class similar to QSignalMapper, but instead of mapping a signal you just forward it. Instead of using disconnect() you could then just delete your instance of SignalProxy. Your original signal could have the queued connection to the SignalProxy and the SignalProxy can have a direct connection to your original slot.

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by
                              #14

                              @SimonSchroeder
                              Which I think is the same sort of thing as I suggested earlier:

                              Or similarly to avoid having to change the actual slot function code, have the connect go via an intermediate slot which does this testing work and calls the real slot if the flag is clear. Ugly, but so are the other proposals....

                              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