On Friday, 5 January 2024 12:56:03 -03 Alexander Dyagilev wrote: > Hello, > > Let's suppose we have an object A with slot AA living in thread AAA. > > Let's suppose we have an object B with signal BB living in thread BBB. > > Let's suppose we've created a direct signal/slot connection from BB to AA. > > Question: is it possible that BB can call AA after it was destroyed? I mean > race condition bug (we have 2 threads). I.e. is connection 100% always > destroyed before A is destroyed?
The connection is, but the answer is more complicated than that. The signal-slot connection mechanism is thread-safe. You can connect and disconnect signals to slots while emitting them. Because the signal activation mechanism locks the receiver's connection list, it will either find the connection intact or it will find the connection torn down. So if you race connections and disconnections with emissions, you will find that some slots may be called or not, depending on timing. This is the answer to the question asked above, but not what you wanted to know. This protection offers a modicum of protection against deletion too, but that is not guaranteed. So my recommendation is that you invest in a mutex and stop reading this reply. This lock does apply in QObject's destructor, so again there's a synchronisation between the emission in thread BBV and the deletion in thread AAA. If the connection were Auto or QueuedConnection, that would result in an event being posted to the object, which would either be delivered *before* the deletion began or would be discarded by the deletion so no delivery happens. This means with Auto or QueuedConnections, you can't really race the deletion. > Well, it seems I just understood. BBB see the connection and starts calling > AA. Then, CPU switch occurs. Thread BBB suspended and AAA resuming. AAA > destroys A. Then BBB resuming and continues to call AA. And we get a crash. > Am I right here? In the case of DirectConnection, no such protection occurs because QObject must drop the locks before invoking your slot. It's the same as your getting the pointer address for AA from somewhere else and directly calling it. YOU must ensure that the object stays alive until your signal emission has finished. That's a mutex. Just so we're clear, there's also the case of the deletion happening while the execution is happening, with no context switches. It's possible the signal activation code blocked the QObject destructor from proceeding... but at that point, object AA is no longer of type A, but of type QObject. This is already wrong. That means you must prevent object BB from starting its deletion in the first place, not from completing it. That is, a mutex inside the object is usually wrong: it must be outside. -- Thiago Macieira - thiago.macieira (AT) intel.com Cloud Software Architect - Intel DCAI Cloud Engineering
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest