C++ Logo

std-proposals

Advanced search

Re: Signals & Slots

From: Tony V E <tvaneerd_at_[hidden]>
Date: Fri, 23 Jul 2021 18:11:12 -0400
On Fri, Jul 23, 2021 at 4:39 PM Thiago Macieira via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Friday, 23 July 2021 13:26:49 PDT Tony V E wrote:
> > Does Qt hold a lock on the current slot when calling the slot?
>
> Slots are not objects that can be locked. They are just functions.
>

Sure. I mean a lock that represents/protects that slot.


>
> > Boost.Signals2 doesn't lock the *list* of slots, but locks the individual
> > slot.
> >
> > If another thread tries to disconnect the currently executing slot (say,
> > because the slot target is being deleted) then it *must* wait for the
> slot
> > to finish (else the slot might crash).
> > If it must wait, it must hold a lock.
>
> Right, the list is locked, but gets unlocked before every slot is called.
> So
> those things end up operating independently. If the signal activation
> decided
> to call that slot before it was disconnected, then it will get called. If
> the
> disconnection happened first, then it won't.
>
>
And that's fine for DirectActivation.



> > Qt (I think) avoids this because it uses an event queue - slots across
> > threads are not called directly, they are queued. When an object is
> > deleted, you "just" need to remove the to-be-called slot from the queue.
> > The Qt idea that an object "lives" on a specific thread is a great way of
> > dealing with many things.
>
> Only for Qt::QueuedActivation.


Yeah, that's the case I'm talking about. Which is the case for objects
living on other threads (unless someone is brave enough to force a
interthread connection to be Direct).


> Qt::DirectActivation (which is the default for
> target objects living in the current thread) does not queue up. It does as
> described above: drop the lock, call, reacquire the lock.
>
>


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



>
> > Without a separate (global/findable) queue, you either hold a lock
> (risking
> > deadlock) or don't hold a lock and risk crashing.
>
> Or you drop the lock and don't crash.
>

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.

Before destroying your object, you want to make sure all connections are
disconnected. So you can call disconnect. But is there a slot in progress
in another thread? The only way (sans queue) disconnect() can know is by
waiting.

In general, you want the contract of disconnect() to be "a slot will not be
called after disconnection". Seems like a simple and reasonable guarantee.
But it is hard. Either disconnect() needs to *wait* for a slot to finish,
or cross-thread slots are queued, and disconnect() empties the queue of
pending slots.
Furthermore, emptying the queue would need to wait for the current
in-progress queue event to finish (if it was a slot), but in Qt that's fine
because the delete is happening in that same thread. If a slot is in
progress, the delete is happening _in that slot_.

Qt avoids the slot or list lock *because* it uses queues for the async
slots.
I suppose if I did an explicit DirectActivation connection across threads,
I could demonstrate the problem scenario in Qt, but the rule in Qt is just
don't do DirectActivation across threads, or at least be very careful if
you do.


>
> The connection list has a flag saying "in use", which means the list can't
> be
> shrunk or garbage collected. Disconnections can still happen by removing
> the
> effect of the entry in the list, but the size of list doesn't change.
>
>
Yes, that's fine for the list handling.


> Then we just need to prevent livelocks: what happens if you *connect*
> something else to the same signal that is being activated, every time that
> a
> given slot is activated?
>

Yeah, do you get added to the end of the current list (ie will your slot be
called on this signal), or wait for the next signal? I say wait for the
next signal.




>
> --
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
> Software Architect - Intel DPG Cloud Engineering
>
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>


-- 
Be seeing you,
Tony

Received on 2021-07-23 17:11:29