Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will disconnecting all signal-slot connections during the execution of a slot prevent all subsequent slots from being called?

Say I have a Qt application where I have something like this:

connect(A, SIGNAL(a()), B, SLOT(b1()));
connect(A, SIGNAL(a()), B, SLOT(b2()));
...
void B::b1() {
  A->disconnect();
}

If a() is emitted, will the slot B::b2() still be called after disconnecting all slots from A in B::b1(), since they both respond to the same signal? Assume that both objects live in the same thread, so we have a direct connection.

I know that the disconnect() disconnects all signal connections from A, but I am not sure if the emit just schedules both the b1 and b2 slots to be called and then calls them, so that a change to the connections has no effect until the two slots (and therefore the emit) return. So it could be implemented like:

emit:
  make temprorary copy of signal's slot table
  foreach element in temporary slot table: call

disconnect:
  clear signal's slot table

Otherwise you could run into datastructure integrity problems.

like image 267
Christian Rau Avatar asked May 13 '11 13:05

Christian Rau


People also ask

How do you turn off signals in Qt?

QMetaObject::Connection myConnect; myConnect=connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom())); ... disconnect(& myConnect);

In what order will the slots be executed if they are connected to one signal?

If several slots are connected to one signal, the slots will be executed one after the other, in the order they have been connected, when the signal is emitted. Signals are automatically generated by the moc and must not be implemented in the .

What is signal slot connection?

A slot is called when a signal connected to it is emitted. Slots are normal C++ functions and can be called normally; their only special feature is that signals can be connected to them. A slot's arguments cannot have default values, and, like signals, it is rarely wise to use your own custom types for slot arguments.

Can we connect one signal with multiple slots?

One signal can be connected to many slots: When the signal is emitted, the slots are called one after the other, in an unspecified order.


1 Answers

A quick experiment shows that the second slot is not called.

However, I'm not sure if this is something that Qt promises.

Qt does document that certain checks are made during the iteration of connected receivers, but it's but that's pretty loose and non-specific (and I haven't come across anything better in my short search); from http://doc.qt.io/qt-5/signalsandslots.html:

This is the overhead required to locate the connection object, to safely iterate over all connections (i.e. checking that subsequent receivers have not been destroyed during the emission)

So they loosely document that certain checks are made while a signal is emitted, such as whether a receiver has been destroyed. I think checking whether the connection has been disconnected seems like a similar kind of situation, but it would be nice if that were explicitly documented.

Since it sounds like this will be a problem for you (you want all the signals to get through, right?), you may be able to work around this problem by ensuring that the signal to slot b1() is connected last. Qt does promise that slots will be called by a signal in connection order, so if you arrange for the slot that does the disconnect to be the last one, all the other slots will be seen.

I don't know how easy this might be to arrange, but it also seems kind of strange that an object would disconnect everything from inside another object's slot function (so there's probably some other refactoring that can solve this problem as well).

If none of that is acceptable, it wouldn't be too hard to come up with a proxy object for A's signals that has the behavior you need. There would be a single:

connect(A, SIGNAL(a()), proxy_obj, SLOT(proxy_slot()));

to connect A's signal to the proxy, then B can connect to the proxy's signal (which the proxy would be emit when the proxy's slot got called):

connect(proxy_obj, SIGNAL(a()), B, SLOT(b1()));
connect(proxy_obj, SIGNAL(a()), B, SLOT(b2()));

Since A's disconnect will not affect the connections that the proxy has to B, the proxy will ensure that all of B's slots get called when signal A->a() is emitted.

class A_proxy : public QObject
{
    Q_OBJECT
public slots:
    void proxy_slot() {
        emit a();
    }

signals:
    void a();
};
like image 68
Michael Burr Avatar answered Nov 15 '22 10:11

Michael Burr