diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 066e9e390a6..a936d189f4c 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -438,6 +438,15 @@ QThread::QThread(QThreadPrivate &dd, QObject *parent) isFinished() returns \c false) will result in a program crash. Wait for the finished() signal before deleting the QThread. + + Since Qt 6.3, it is allowed to delete a QThread instance created by + a call to QThread::create() even if the corresponding thread is + still running. In such a case, Qt will post an interruption request + to that thread (via requestInterruption()); will ask the thread's + event loop (if any) to quit (via quit()); and will block until the + thread has finished. + + \sa create(), isInterruptionRequested(), exec(), quit() */ QThread::~QThread() { @@ -1101,6 +1110,13 @@ public: { } + ~QThreadCreateThread() + { + requestInterruption(); + quit(); + wait(); + } + private: void run() override { diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index d4950cd42b6..b9c5eeb2432 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,7 @@ private slots: void quitLock(); void create(); + void createDestruction(); void threadIdReuse(); }; @@ -1591,6 +1593,66 @@ void tst_QThread::create() #endif // QT_CONFIG(cxx11_future) } +void tst_QThread::createDestruction() +{ + for (int delay : {0, 10, 20}) { + auto checkForInterruptions = []() { + for (;;) { + if (QThread::currentThread()->isInterruptionRequested()) + return; + QThread::msleep(1); + } + }; + + QScopedPointer thread(QThread::create(checkForInterruptions)); + QSignalSpy finishedSpy(thread.get(), &QThread::finished); + QVERIFY(finishedSpy.isValid()); + + thread->start(); + if (delay) + QThread::msleep(delay); + thread.reset(); + + QCOMPARE(finishedSpy.size(), 1); + } + + for (int delay : {0, 10, 20}) { + auto runEventLoop = []() { + QEventLoop loop; + loop.exec(); + }; + + QScopedPointer thread(QThread::create(runEventLoop)); + QSignalSpy finishedSpy(thread.get(), &QThread::finished); + QVERIFY(finishedSpy.isValid()); + + thread->start(); + if (delay) + QThread::msleep(delay); + thread.reset(); + + QCOMPARE(finishedSpy.size(), 1); + } + + for (int delay : {0, 10, 20}) { + auto runEventLoop = [delay]() { + if (delay) + QThread::msleep(delay); + QEventLoop loop; + loop.exec(); + }; + + QScopedPointer thread(QThread::create(runEventLoop)); + QSignalSpy finishedSpy(thread.get(), &QThread::finished); + QVERIFY(finishedSpy.isValid()); + + thread->start(); + thread.reset(); + + QCOMPARE(finishedSpy.size(), 1); + } +} + class StopableJob : public QObject { Q_OBJECT