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

Do cross-thread slot invocations prolong sender's lifetime?



  • Hello!

    Let's imagine we have 2 objects in 2 distinct threads. Object 2's slot is connected to Object 1's signal. Signal is emitted, and Object 2's slot is called. Then, someone invokes object1->deleteLater() in the middle of slot invocation. Will slot's sender() become dangling pointer? Or will slot prolong sender's life until it's finished? If the former, how would one guard against such case?

    Please note objects belong to independent event loops.

    I found topic https://forum.qt.io/topic/243/cross-thread-signals-disconnect-and-destructors but it discusses only about disconnection and not about mid-flight sender's deletion.

    Thanks,
    Igor


  • Lifetime Qt Champion

    @Igor-Baidiuk Not direct answer: you should avoid using sender() anyway. With C++11 lambdas there is usually no need to use sender() and using sender() you invent tight coupling which is not good from architecture point of view.



  • @jsulm Thanks but that's not the case. I have exactly 2 objects, one of them depends on the state of the other.
    To be more precise, they're two tree-like data structures. One presents data of certain hierarchical 3D model, other is the respective scene graph. They live in separate threads because of QML's rendering. I need scene nodes be notified of model nodes' changes directly, signal being the easiest way. Like when some assembly gets one of its children removed, or leaf body changes its geometry etc.



  • @Igor-Baidiuk
    But that does not mean you have to use sender(). As @jsulm said, you can preferably use a lambda parameter instead.



  • I still don't get what does lambda have with this. If I even add sender's address to lambda's capture list, it'll end just like sender().


  • Lifetime Qt Champion

    @Igor-Baidiuk Can you explain why you need sender() at all?
    Why does the slot need to know anything about signal emitter? What do you do with sender object in the slot?



  • void onGeometryChanged() {
        auto mesh = static_cast<Mesh*>(sender());
        auto vBuffer = createVertexBuffer(mesh->vertices());
        // (1) someone deletes sender in another thread
        auto idxBuffer = createTrianglesBuffer(mesh->triangles()); // <-- kaboom due to (1)?
        ...
    }
    

  • Lifetime Qt Champion

    Then pass the mesh pointer to onGeometryChanged() slot as already said two times. Take a look at the new signal/slot syntax wiki page when you don't how to use a lambda for this.



  • With all due respect, I asked specific question. And I know about new signal/slot binding. I know I can create proxy lambda. But, again, this was not my question. If you know answer, I'd appreciate if you share it. If you don't, why consistently telling me where's the fridge if I'm looking for bicycle?

    EDIT: BTW connecting lambda does not allow tying its lifetime to receiver since there's no receiver. So if real receiver referenced in lambda gets deleted, hello segfault. Even if I use QPointer, it'll result in resource leak.


  • Lifetime Qt Champion

    @Igor-Baidiuk said in Do cross-thread slot invocations prolong sender's lifetime?:

    If you know answer, I'd appreciate if you share it.

    We already told you the answer. Pass the pointer via lambda to your slot similar as explained in the wiki:

    QString newValue = "blub";
    connect(
        sender, &Sender::valueChanged,
        [=]( const QString &newValue ) { receiver->updateValue( "senderValue", newValue ); }
    );
    

  • Qt Champions 2017

    @Igor-Baidiuk said in Do cross-thread slot invocations prolong sender's lifetime?:

    Will slot's sender() become dangling pointer?

    It may. Taking the sender() of a queued invocation is UB.

    Or will slot prolong sender's life until it's finished?

    It will not.

    If the former, how would one guard against such case?

    You yourself must guarantee that the object is alive until that time; usual MT considerations apply. Best advice - define clear lifetimes of your objects. If you need said object at some point to be alive, then make sure nobody is deleting it in the meantime. Furthermore operating on an object in a different thread without serialization is a race. You can keep a QPointer to some QObject if you need an non-owning signaled pointer.



  • @kshegunov

    It may. Taking the sender() of a queued invocation is UB.

    It will not.

    Thank you very much. This fully answers my question.


Log in to reply