When you disconnect a signal from a slot, any queued connections that have already been made will still be delivered. How clear queued connection ?
-
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 -
@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 thatWhen you do
emit completed()
, it makes sense for the signal to immediately activate or queue all connected slotsbut 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.... -
@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 byQCoreApplication::postEvent
.
But this will clear all the queued connections of thereceiver
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 likeif(!sender()) return;
-
@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?
-
@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;
-
@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 -
@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".
-
@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. -
@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 secondonTimeoutQueued
to have been output afterDisconnected
. I don't see how that explanation holds up here? -
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 :) -
@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 thetimeout
signal from theQTimer
, 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 theemit
. 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?
-
I believe that queued connections are not delivered if the receiver is delete (not via
deleteLater()
!). This brings up the idea to have aSignalProxy
class similar toQSignalMapper
, but instead of mapping a signal you just forward it. Instead of usingdisconnect()
you could then just delete your instance ofSignalProxy
. Your original signal could have the queued connection to the SignalProxy and the SignalProxy can have a direct connection to your original slot. -
@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....