QThreadStorage: don't print the destruction ordering warning on app exit

This warning here was very confusing (so I'm also updating the language
to be clearer what it means). It is here to advise users of
QThreadStorage that they may have destroyed the object before all
threads using the object have finished. That means there will be memory
leaks, hence the user should fix the issue.

But the one time we don't care (too much) about memory leaks is when the
application is about to exit -- all memory is being released back to the
OS anyway. This may happen because of Static De-Initialization Order
Fiasco: the Q_GLOBAL_STATIC or equivalents holding QThreadStorage were
destroyed before the QThreadData for the exit()ing thread did. That
problem became more prevalent after the series of changes ending in
commit 2f69a05bd0cd7ce63890f709ff3ed7a4f78acd70, because that made the
QThreadData clean up happen very late in the execution.

Unfortunately, there's no way for us to know when we're being called
during application exit, so this is the next best thing:
QCoreApplication::instance() does not exist. We're using a private
function in QCoreApplication because in Qt 6.x, QCoreApplication::self
is not atomic and reading it would be a data race.

The QThread::currentThread() call was superfluous, because it was always
true. It was a relic from Qt 3, from before we had QAdoptedThread.

Fixes: QTBUG-133500
Change-Id: I48d84d76f2b72483ed92fffdd54c6ad17e3d67d3
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit fd857d400a098598072ff08b0a54f4ba2589357b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 56993ad55964c271dd493a3a60b737c91f31a5b5)
This commit is contained in:
Thiago Macieira 2025-02-08 14:59:39 -08:00 committed by Qt Cherry-pick Bot
parent 2dbdbbbcf5
commit 2c8b1dc959
3 changed files with 10 additions and 3 deletions

View File

@ -489,6 +489,11 @@ QCoreApplicationPrivate::~QCoreApplicationPrivate()
QCoreApplicationPrivate::clearApplicationFilePath();
}
bool QCoreApplicationPrivate::isAlive() noexcept
{
return qApp != nullptr;
}
#ifndef QT_NO_QOBJECT
void QCoreApplicationPrivate::cleanupThreadData()

View File

@ -64,6 +64,7 @@ public:
#endif
~QCoreApplicationPrivate();
static bool isAlive() noexcept;
void init();
QString appName() const;

View File

@ -3,6 +3,7 @@
#include "qthreadstorage.h"
#include "private/qcoreapplication_p.h"
#include "qthread.h"
#include "qthread_p.h"
#include "qmutex.h"
@ -156,9 +157,9 @@ void QThreadStorageData::finish(void **p)
locker.unlock();
if (!destructor) {
if (QThread::currentThread())
qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed",
QThread::currentThread(), i);
if (QCoreApplicationPrivate::isAlive())
qWarning("QThreadStorage: entry %d destroyed before end of thread %p",
i, QThread::currentThread());
continue;
}
destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed