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
http://lists.qt-project.org/mailman/listinfo/interest

Reply via email to