Hi.

That does help, thanks. It means that I’d really need to use an arbitrarily 
long timer, or find the “proper” solution.

At one stage I thought about having a C++ object that could be created in QML 
and would somehow keep count of references to the game object. For example, 
each Loader whose source component has access to the game object would somehow 
register itself with the object, and the game wouldn’t start quitting until all 
references were gone. As long as the C++ doesn’t know about the UI, I think it 
could work quite well.

Something like this:

Loader {
    // ... contains GameView
}

// GameView.qml

Item {
    id: root
    property alias game

    GameScope {
        game: root.game
    }
}

// GameScope.cpp

GameScope::setGame(Game *game)
{
    if (game == mGame)
        return;

    if (game)
        game->increaseReferenceCount();
    else
        game->decreaseReferenceCount();

    mGame = game;
}

GameScope::~GameScope()
{
    if (game)
        game->decreaseReferenceCount();
}


Each event loop after a quit has been requested, Game could check the reference 
count and begin the actual quitting if it’s 0.

It still feels like it shouldn’t be necessary, but at least there’s no 
guesswork involved.

From: Nye [mailto:kshegu...@gmail.com]
Sent: Tuesday, 22 March 2016 10:33 PM
To: Curtis Mitch <mitch.cur...@theqtcompany.com>
Cc: interest@qt-project.org
Subject: Re: [Interest] Ensuring that a queued invocation occurs after deferred 
deletion

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.cur...@theqtcompany.com<mailto:mitch.cur...@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@qt-project.org<mailto:Interest@qt-project.org>
http://lists.qt-project.org/mailman/listinfo/interest

_______________________________________________
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest

Reply via email to