Date: Fri, 23 Jul 2021 15:49:42 -0700
On Friday, 23 July 2021 15:11:12 PDT Tony V E wrote:
> As for queued activations already queued but not yet delivered, the
> destruction of the target object removes all pending events from the event
> queue.
>
> Yeah, that's the special sauce that avoids the problems. In the general
> (non-Qt) case, you don't have a queue mechanism to fall back on.
[...]
> You don't crash because you never delete an object from thread A while the
> slot is running from thread B.
>
> In the non-Qt non-queue-available-for-threads world, you can't synchronize
> the deletion from thread A with a slot from thread B.
I see what you mean. Thanks for clarifying. This is another difference between
the 3- and 4-argument versions of connect:
connect(sender, &Sender::itHappened, [=] { receiver->act(); });
vs
connect(sender, &Sender::itHappened, receiver, [=] { receiver->act(); });
The 3-argument version has no idea what the lambda it was passed does. The
lifetime of the connection is bound to the sender only and the activation will
always be direct.
The 4-argument version has extra context. The lifetime of the connection is
bound to both sender and receiver, so it's disconnected when either is
destroyed, whichever happens first. That means it will not outlive the
receiver and cause a dangling pointer dereference. And it'll also activate in
the receiver's thread, as discussed.
> As for queued activations already queued but not yet delivered, the
> destruction of the target object removes all pending events from the event
> queue.
>
> Yeah, that's the special sauce that avoids the problems. In the general
> (non-Qt) case, you don't have a queue mechanism to fall back on.
[...]
> You don't crash because you never delete an object from thread A while the
> slot is running from thread B.
>
> In the non-Qt non-queue-available-for-threads world, you can't synchronize
> the deletion from thread A with a slot from thread B.
I see what you mean. Thanks for clarifying. This is another difference between
the 3- and 4-argument versions of connect:
connect(sender, &Sender::itHappened, [=] { receiver->act(); });
vs
connect(sender, &Sender::itHappened, receiver, [=] { receiver->act(); });
The 3-argument version has no idea what the lambda it was passed does. The
lifetime of the connection is bound to the sender only and the activation will
always be direct.
The 4-argument version has extra context. The lifetime of the connection is
bound to both sender and receiver, so it's disconnected when either is
destroyed, whichever happens first. That means it will not outlive the
receiver and cause a dangling pointer dereference. And it'll also activate in
the receiver's thread, as discussed.
-- Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org Software Architect - Intel DPG Cloud Engineering
Received on 2021-07-23 17:49:51