From 87535e4e4337596066258e361143cb9906e89512 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 19 Apr 2023 17:49:14 +0200 Subject: QTimer: optimize single shot timers that cross thread Amend 4d90c4e74a6aa34d5aabfb91ec304da1f02df3e3 by clarifying why moving the QSingleShotObject to the receiver's thread is a good idea. Move that logic into a separate function and use that also for the string-based connection. Optimize the implementation by delaying the timer creation until after we have moved the QSingleShotTimer object to the target thread, using a queued metacall if needed to create the timer. This avoids the creation of the timer in the wrong thread and then the recreation of the timer in the new thread when QObject handles QEvent::ThreadChange. To avoid that the timer is created when it has already expired in real time, use a deadline timer and fire timeout immediately when it has expired by the time we get the metacall. Since the timerId might now not be initialized in the constructor, initialize it to -1. Augment the crossThreadSingleShotToFunctor test function by deliberately not starting the thread until the deadline expired. [ChangeLog][Core][QTimer] Single-shot timers with a string-based connection are now started in the receiver's thread, not in the thread that creates the timer. Task-number: QTBUG-112162 Change-Id: I3fc94c34c21d9f644da41a2e4c2da479980b8580 Reviewed-by: Thiago Macieira --- tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'tests/auto/corelib/kernel/qtimer') diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 2e86d89923..b4f7aa5bd8 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -1031,11 +1031,22 @@ void tst_QTimer::crossThreadSingleShotToFunctor() DummyFunctor::callThread = nullptr; QThread t; - t.start(); - std::unique_ptr o(new QObject()); o->moveToThread(&t); + QTimer::singleShot(timeout, o.get(), DummyFunctor()); + + // wait enough time for the timer to have timed out before the timer + // could be start in the receiver's thread. + QTest::qWait(10 + timeout * 10); + t.start(); + t.wait(); + QCOMPARE(DummyFunctor::callThread, &t); + + // continue with a stress test - the calling thread is busy, the + // timer should still fire and no crashes. + DummyFunctor::callThread = nullptr; + t.start(); for (int i = 0; i < 10000; i++) QTimer::singleShot(timeout, o.get(), DummyFunctor()); -- cgit v1.2.3