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.
  • 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