Passing QObjects across threads via signals and slots
-
[Forked from https://forum.qt.io/topic/125838/can-i-use-myclass-in-qt-signal-and-slots/ --JKSH]
@JKSH
I don't use threads, nor need to emit signals passing my own classes, so this is purely a for-my-information.So even for
const MyClass&
you are saying Qt copies the instance? Which would rule out anythingQObject
-derived. There isn't a way to just pass a const reference to the original across threads? -
@JonB said in can I use MyClass& in Qt signal and slots?:
Qt copies the instance
For queued connections (default for across threads) it does
-
@jsulm said in can I use MyClass& in Qt signal and slots?:
it does
There is no other chance than copying it :)
-
@JonB said in can I use MyClass& in Qt signal and slots?:
So even for const MyClass& you are saying Qt copies the instance? Which would rule out anything QObject-derived. There isn't a way to just pass a const reference to the original across threads?
With Qt, @JonB means
QMetaObject::activate()
, which is called when emitting a signal.
Because source and destination are in different thread, this method is kind enough to create a copy of the current instance and pass the copy to the called slot/functor.Of course the
QMetaObject
needs to be aware about how to create a copy, so you have to register the type withqRegisterMetaType()
. And the class needs to implement a copy constructor. -
@jsulm , @Christian-Ehrlicher , @KroMignon
Hmm, interesting, thank you. So for example noconst QObject &
is possible.Maybe I'm thinking too much about references,
&
. I can instead pass a pointer,const QObject *
, right? Provided I am careful about lifetime and read-writes, that is OK? (And I don't needqRegisterMetaType()
for that?) -
@JonB said in can I use MyClass& in Qt signal and slots?:
Provided I am careful about lifetime and read-writes, that is OK?
Yes, but very error-prone.
-
@JonB said in can I use MyClass& in Qt signal and slots?:
Hmm, interesting, thank you. So for example no const QObject & is possible.
There are more than one level to take in account:
- the signature of signal
- the signature of slot
- the
QMetaObject::activate()
call
Using
const QObject &
for signal does only means that when calling the signal function, no copy will be done.
But as sender and receiver are in different threads,QMetaObject::activate()
will create a copy of parameter before add slot call in receiver thread QEventLoop. -
@KroMignon said in can I use MyClass& in Qt signal and slots?:
Using const QObject & for signal does only means that when calling the signal function, no copy will be done.
But as sender and receiver are in different threads, QMetaObject::activate() will create a copy of parameter before add slot call in receiver thread QEventLoop.But since
QObject
is not copyable I don't see how this case would be allowed?Since you are all saying that neither
&
nor*
are good forQObject
across threads, does this mean in practice that you cannot pass aQObject
from a signal to a slot?I am getting very lost now. Because when people ask "how do I pass the widget which caused a signal to the slot if that's what I need to do" one of the possible answers we give is "write a lambda which accepts the widget as an extra parameter", like:
connect(checkbox, &QCheckBox::pressed, that, [checkbox]() { qDebug() << checkbox; });
Maybe this doesn't count as a parameter. But from Python this would be:
checkbox.pressed.connect(lambda checkbox=checkbox: print(checkbox))
There's no difference in Python lambdas between what goes in the
[...]
versus(...)
from the C++ lambda.My head hurts.... :)
-
@JonB said in can I use MyClass& in Qt signal and slots?:
But since QObject is not copyable I don't see how this case would be allowed?
This case is not possible/allowed ;) That's the point.
when sender and receiver are in different threads, all parameter types needs to have a copy constructor and have to be registered with qRegisterMetaType().QObject bassed type cannot be used for cross-threaded or queued connection.
-
@JonB said in Passing QObjects across threads via signals and slots:
does this mean in practice that you cannot pass a
QObject
from a signal to a slot?Yes, you can.
QNetworkAccessManager::finished(QNetworkReply*)
is one such signal; QNetworkReply is a QObject.Since you are all saying that neither
&
nor*
are good forQObject
across threadsHold up. Take a deep breath. Let's untangle things a bit.
- You cannot use
const QObject&
as a signal/slot argument between threads, ever. Because QObjects are not copyable. - You can use
QObject*
as a signal/slot argument between threads. @Christian-Ehrlicher and @mrjj did not say it's not allowed; they said it's dangerous.
I am getting very lost now. Because when people ask "how do I pass the widget which caused a signal to the slot if that's what I need to do" one of the possible answers we give is "write a lambda which accepts the widget as an extra parameter", like:
connect(checkbox, &QCheckBox::pressed, that, [checkbox]() { qDebug() << checkbox; });
Well, there's no multithreading here. So it's not dangerous.
- You cannot use