[Interest] Ensuring that a queued invocation occurs after deferred deletion

Nye kshegunov at gmail.com
Tue Mar 22 22:33:26 CET 2016


Hello,
I don't work with QML, but I'm pretty sure the events are processed in the
order of their appearance in the event queue. So if you have a
`deleteLater` call (i.e. you have a QEvent::DeferredDelete, which is
scheduled through the event loop) any queued call to a slot (i.e.
QEvent::MetaCall) that was made before the deletion request should be
happening before the actual deletion. So, if you're emitting signals from a
single thread, their respective slots would be called in the order in which
the signals had happened.

Now, with multiple threads it's a bit tricky, since there's the chance that
two threads will be trying to post a deferred function invocation at the
same time (hence the event queue is protected by a mutex). However that
mutex can't guarantee in what order the events will be posted, or rather no
one can.

> My only thought is to use a zero-second single-shot timer. The question
is: is this guaranteed to happen *after* deferred deletion for a given
iteration of an event loop?

This posts a timer event on the queue, so you can achieve the same with
QMetaObject::invokeMethod(receiverObject, "method", Qt::QueuedConnection),
and the same "restrictions" apply as mentioned above.

I hope this is of help.
Kind regards.

On Tue, Mar 22, 2016 at 7:50 PM, Curtis Mitch <mitch.curtis at theqtcompany.com
> wrote:

>
> I recently discovered [1] that Loader defers deletion of items via
> deleteLater(). Up until that point, I had been treating certain operations
> in my program as synchronous (as I haven't introduced threads yet). Now
> that I can't safely assume that UI items will be instantly destroyed, I
> have to convert these operations into asynchronous ones.
>
> For example, previously, I had this code:
>
> game.quitGame();
>
> My idea is to turn it into this:
>
> game.requestQuitGame();
>
> Within this function, the Game object would set its "ready" property to
> false, emitting its associated property change signal so that Loaders can
> set active to false. Then, QMetaObject::invoke would be called with
> Qt::QueuedConnection to ensure that the Loader's deleteLater() calls would
> have been carried out *before* tearing down the game and its objects.
>
> In order to confirm that invokeMethod() works the way I thought it did, I
> added the following debug statements to QEventLoop:
>
> diff --git a/src/corelib/kernel/qeventloop.cpp
> b/src/corelib/kernel/qeventloop.cpp
> index dca25ce..7dae9d0 100644
> --- a/src/corelib/kernel/qeventloop.cpp
> +++ b/src/corelib/kernel/qeventloop.cpp
> @@ -151,6 +151,7 @@ bool QEventLoop::processEvents(ProcessEventsFlags
> flags)
>
>      \sa QCoreApplication::quit(), exit(), processEvents()
>  */
> +#include <QDebug>
>  int QEventLoop::exec(ProcessEventsFlags flags)
>  {
>      Q_D(QEventLoop);
> @@ -200,8 +201,11 @@ int QEventLoop::exec(ProcessEventsFlags flags)
>      if (app && app->thread() == thread())
>          QCoreApplication::removePostedEvents(app, QEvent::Quit);
>
> -    while (!d->exit.loadAcquire())
> +    while (!d->exit.loadAcquire()) {
> +        qDebug() << Q_FUNC_INFO << "--- beginning event loop";
>          processEvents(flags | WaitForMoreEvents | EventLoopExec);
> +        qDebug() << Q_FUNC_INFO << "--- ending event loop";
> +    }
>
>      ref.exceptionCaught = false;
>      return d->returnCode.load();
>
> It turns out that I misunderstood the documentation; it only says that the
> slot is invoked when control returns to the event loop of the receiver's
> thread. So, as I understand it, it's possible that the invocation could
> happen *before* the deferred deletion of the Loaders' items. As the
> documentation doesn't specify the order between these two things, I should
> probably assume that it's not safe to assume anything.
>
> So, I'm left with the problem of how to ensure that a slot is invoked
> after the Loaders' items have been destroyed. My only thought is to use a
> zero-second single-shot timer. The question is: is this guaranteed to
> happen *after* deferred deletion for a given iteration of an event loop? I
> can't see such a guarantee in the documentation. I even checked the source
> code of e.g. qeventdispatcher_win.cpp to see if I could find anything,
> without success.
>
> Another question that's in the back of my mind is: is there a better way
> to do this?
>
> [1] https://bugreports.qt.io/browse/QTBUG-51995
> [2] http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20160322/de27d695/attachment.html>


More information about the Interest mailing list