Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 anything QObject-derived. There isn't a way to just pass a const reference to the original across threads?


  • Lifetime Qt Champion

    @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


  • Lifetime Qt Champion

    @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 with qRegisterMetaType(). And the class needs to implement a copy constructor.



  • @jsulm , @Christian-Ehrlicher , @KroMignon
    Hmm, interesting, thank you. So for example no const 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 need qRegisterMetaType() for that?)


  • Lifetime Qt Champion

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


  • Lifetime Qt Champion

    @JonB
    Hi
    Sending raw pointers between threads is as recommended
    as using a torch to investigate why all the electrical powers went out
    in the Gasoline factory. 💥😜



  • @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 for QObject across threads, does this mean in practice that you cannot pass a QObject 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.


  • Moderators

    @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 for QObject across threads

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


Log in to reply