diff options
Diffstat (limited to 'src/corelib/thread/qthread.cpp')
-rw-r--r-- | src/corelib/thread/qthread.cpp | 181 |
1 files changed, 150 insertions, 31 deletions
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 08a010124a..8d8f353aaa 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -65,9 +65,10 @@ QThreadData::~QThreadData() // crashing during QCoreApplicationData's global static cleanup we need to // safeguard the main thread here.. This fix is a bit crude, but it solves // the problem... - if (this->thread.loadAcquire() == QCoreApplicationPrivate::theMainThread.loadAcquire()) { - QCoreApplicationPrivate::theMainThread.storeRelease(nullptr); - QThreadData::clearCurrentThreadData(); + if (threadId.loadAcquire() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) { + QCoreApplicationPrivate::theMainThread.storeRelease(nullptr); + QCoreApplicationPrivate::theMainThreadId.storeRelaxed(nullptr); + QThreadData::clearCurrentThreadData(); } // ~QThread() sets thread to nullptr, so if it isn't null here, it's @@ -129,8 +130,9 @@ QAdoptedThread::QAdoptedThread(QThreadData *data) d_func()->running = true; d_func()->finished = false; init(); + d_func()->m_statusOrPendingObjects.setStatusAndClearList( + QtPrivate::getBindingStatus({})); #endif - // fprintf(stderr, "new QAdoptedThread = %p\n", this); } @@ -145,7 +147,24 @@ void QAdoptedThread::run() // this function should never be called qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called."); } +#endif + +QScopedScopeLevelCounter::QScopedScopeLevelCounter(QThreadData *threadData) + : threadData(threadData) +{ + ++threadData->scopeLevel; + qCDebug(lcDeleteLater) << "Increased" << threadData->thread + << "scope level to" << threadData->scopeLevel; +} +QScopedScopeLevelCounter::~QScopedScopeLevelCounter() +{ + --threadData->scopeLevel; + qCDebug(lcDeleteLater) << "Decreased" << threadData->thread + << "scope level to" << threadData->scopeLevel; +} + +#if QT_CONFIG(thread) /* QThreadPrivate */ @@ -255,22 +274,21 @@ QThreadPrivate::~QThreadPrivate() documentation for terminate() and setTerminationEnabled() for detailed information. - From Qt 4.8 onwards, it is possible to deallocate objects that - live in a thread that has just ended, by connecting the - finished() signal to QObject::deleteLater(). + You often want to deallocate objects that live in a thread when + a thread ends. To do this, connect the finished() signal to + QObject::deleteLater(). Use wait() to block the calling thread, until the other thread has finished execution (or until a specified time has passed). QThread also provides static, platform independent sleep functions: sleep(), msleep(), and usleep() allow full second, - millisecond, and microsecond resolution respectively. These - functions were made public in Qt 5.0. + millisecond, and microsecond resolution respectively. \note wait() and the sleep() functions should be unnecessary in general, since Qt is an event-driven framework. Instead of wait(), consider listening for the finished() signal. Instead of - the sleep() functions, consider using QTimer. + the sleep() functions, consider using QChronoTimer. The static functions currentThreadId() and currentThread() return identifiers for the currently executing thread. The former @@ -283,11 +301,12 @@ QThreadPrivate::~QThreadPrivate() If you don't call \l{QObject::setObjectName()}{setObjectName()}, the name given to your thread will be the class name of the runtime type of your thread object (for example, \c "RenderThread" in the case of the - \l{Mandelbrot Example}, as that is the name of the QThread subclass). + \l{Mandelbrot} example, as that is the name of the QThread subclass). Note that this is currently not available with release builds on Windows. \sa {Thread Support in Qt}, QThreadStorage, {Synchronizing Threads}, - {Mandelbrot Example}, {Semaphores Example}, {Wait Conditions Example} + Mandelbrot, {Producer and Consumer using Semaphores}, + {Producer and Consumer using Wait Conditions} */ /*! @@ -408,6 +427,23 @@ QThread *QThread::currentThread() } /*! + \since 6.8 + + Returns whether the currently executing thread is the main thread. + + The main thread is the thread in which QCoreApplication was created. + This is usually the thread that called the \c{main()} function, but not necessarily so. + It is the thread that is processing the GUI events and in which graphical objects + (QWindow, QWidget) can be created. + + \sa currentThread(), QCoreApplication::instance() +*/ +bool QThread::isMainThread() +{ + return currentThreadId() == QCoreApplicationPrivate::theMainThreadId.loadRelaxed(); +} + +/*! Constructs a new QThread to manage a new thread. The \a parent takes ownership of the QThread. The thread does not begin executing until start() is called. @@ -604,6 +640,19 @@ QBindingStatus *QtPrivate::BindingStatusOrList::addObjectUnlessAlreadyStatus(QOb return nullptr; } +/*! + \internal + If BindingStatusOrList is a list, remove \a object from it + */ +void QtPrivate::BindingStatusOrList::removeObject(QObject *object) +{ + List *objectList = list(); + if (!objectList) + return; + auto it = std::remove(objectList->begin(), objectList->end(), object); + objectList->erase(it, objectList->end()); +} + QBindingStatus *QThreadPrivate::addObjectWithPendingBindingStatusChange(QObject *obj) { if (auto status = m_statusOrPendingObjects.bindingStatus()) @@ -612,6 +661,15 @@ QBindingStatus *QThreadPrivate::addObjectWithPendingBindingStatusChange(QObject return m_statusOrPendingObjects.addObjectUnlessAlreadyStatus(obj); } +void QThreadPrivate::removeObjectWithPendingBindingStatusChange(QObject *obj) +{ + if (m_statusOrPendingObjects.bindingStatus()) + return; + QMutexLocker lock(&mutex); + m_statusOrPendingObjects.removeObject(obj); +} + + /*! \threadsafe Tells the thread's event loop to exit with a return code. @@ -728,16 +786,28 @@ QThread::Priority QThread::priority() const } /*! - \fn void QThread::sleep(unsigned long secs) + \fn void QThread::sleep(std::chrono::nanoseconds nsecs) + \since 6.6 - Forces the current thread to sleep for \a secs seconds. + Forces the current thread to sleep for \a nsecs. Avoid using this function if you need to wait for a given condition to change. Instead, connect a slot to the signal that indicates the change or use an event handler (see \l QObject::event()). \note This function does not guarantee accuracy. The application may sleep - longer than \a secs under heavy load conditions. + longer than \a nsecs under heavy load conditions. +*/ + +/*! + \fn void QThread::sleep(unsigned long secs) + + Forces the current thread to sleep for \a secs seconds. + + This is an overloaded function, equivalent to calling: + \code + QThread::sleep(std::chrono::seconds{secs}); + \endcode \sa msleep(), usleep() */ @@ -745,11 +815,10 @@ QThread::Priority QThread::priority() const /*! \fn void QThread::msleep(unsigned long msecs) - Forces the current thread to sleep for \a msecs milliseconds. - - Avoid using this function if you need to wait for a given condition to - change. Instead, connect a slot to the signal that indicates the change or - use an event handler (see \l QObject::event()). + This is an overloaded function, equivalent to calling: + \code + QThread::sleep(std::chrono::milliseconds{msecs}); + \endcode \note This function does not guarantee accuracy. The application may sleep longer than \a msecs under heavy load conditions. Some OSes might round \a @@ -761,11 +830,10 @@ QThread::Priority QThread::priority() const /*! \fn void QThread::usleep(unsigned long usecs) - Forces the current thread to sleep for \a usecs microseconds. - - Avoid using this function if you need to wait for a given condition to - change. Instead, connect a slot to the signal that indicates the change or - use an event handler (see \l QObject::event()). + This is an overloaded function, equivalent to calling: + \code + QThread::sleep(std::chrono::microseconds{secs}); + \endcode \note This function does not guarantee accuracy. The application may sleep longer than \a usecs under heavy load conditions. Some OSes might round \a @@ -863,6 +931,36 @@ int QThread::loopLevel() const return d->data->eventLoops.size(); } +/*! + \internal + Returns the thread handle of this thread. + It can be compared with the return value of currentThreadId(). + + This is used to implement isCurrentThread, and might be useful + for debugging (e.g. by comparing the value in gdb with info threads). + + \note Thread handles of destroyed threads might be reused by the + operating system. Storing the return value of this function can + therefore give surprising results if it outlives the QThread object + (threads claimed to be the same even if they aren't). +*/ +Qt::HANDLE QThreadPrivate::threadId() const +{ + return data->threadId.loadRelaxed(); +} + +/*! + \since 6.8 + Returns true if this thread is QThread::currentThread. + + \sa currentThreadId() +*/ +bool QThread::isCurrentThread() const +{ + Q_D(const QThread); + return QThread::currentThreadId() == d->threadId(); +} + #else // QT_CONFIG(thread) QThread::QThread(QObject *parent) @@ -935,6 +1033,11 @@ QThread *QThread::currentThread() return QThreadData::current()->thread.loadAcquire(); } +bool QThread::isCurrentThread() const +{ + return true; +} + int QThread::idealThreadCount() noexcept { return 1; @@ -956,6 +1059,20 @@ bool QThread::isRunning() const return d->running; } +void QThread::requestInterruption() +{ + +} + +bool QThread::isInterruptionRequested() const +{ + return false; +} + +void QThread::setTerminationEnabled(bool) +{ +} + // No threads: so we can just use static variables Q_CONSTINIT static QThreadData *data = nullptr; @@ -967,8 +1084,10 @@ QThreadData *QThreadData::current(bool createIfNecessary) data->threadId.storeRelaxed(Qt::HANDLE(data->thread.loadAcquire())); data->deref(); data->isAdopted = true; - if (!QCoreApplicationPrivate::theMainThread.loadAcquire()) + if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) { QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed()); + QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed()); + } } return data; } @@ -1088,11 +1207,11 @@ bool QThread::event(QEvent *event) void QThread::requestInterruption() { - if (this == QCoreApplicationPrivate::theMainThread.loadAcquire()) { + Q_D(QThread); + if (d->threadId() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) { qWarning("QThread::requestInterruption has no effect on the main thread"); return; } - Q_D(QThread); QMutexLocker locker(&d->mutex); if (!d->running || d->finished || d->isInFinish) return; @@ -1158,7 +1277,6 @@ bool QThread::isInterruptionRequested() const \sa start() */ -#if QT_CONFIG(cxx11_future) class QThreadCreateThread : public QThread { public: @@ -1187,7 +1305,6 @@ QThread *QThread::createThreadImpl(std::future<void> &&future) { return new QThreadCreateThread(std::move(future)); } -#endif // QT_CONFIG(cxx11_future) /*! \class QDaemonThread @@ -1202,7 +1319,9 @@ QDaemonThread::QDaemonThread(QObject *parent) { // QThread::started() is emitted from the thread we start connect(this, &QThread::started, - [](){ QThreadData::current()->requiresCoreApplication = false; }); + this, + [](){ QThreadData::current()->requiresCoreApplication = false; }, + Qt::DirectConnection); } QDaemonThread::~QDaemonThread() |