diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index ee947c0c5f8..aa3bb00b7ba 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -127,8 +127,7 @@ QAdoptedThread::QAdoptedThread(QThreadData *data) // thread should be running and not finished for the lifetime // of the application (even if QCoreApplication goes away) #if QT_CONFIG(thread) - d_func()->running = true; - d_func()->finished = false; + d_func()->threadState = QThreadPrivate::Running; init(); d_func()->m_statusOrPendingObjects.setStatusAndClearList( QtPrivate::getBindingStatus({})); @@ -170,10 +169,7 @@ QScopedScopeLevelCounter::~QScopedScopeLevelCounter() */ QThreadPrivate::QThreadPrivate(QThreadData *d) - : QObjectPrivate(), running(false), finished(false), - isInFinish(false), interruptionRequested(false), - exited(false), returnCode(-1), - stackSize(0), priority(QThread::InheritPriority), data(d) + : QObjectPrivate(), data(d) { // INTEGRITY doesn't support self-extending stack. The default stack size for @@ -492,12 +488,12 @@ QThread::~QThread() Q_D(QThread); { QMutexLocker locker(&d->mutex); - if (d->isInFinish) { + if (d->threadState == QThreadPrivate::Finishing) { locker.unlock(); wait(); locker.relock(); } - if (d->running && !d->finished && !d->data->isAdopted) + if (d->threadState == QThreadPrivate::Running && !d->data->isAdopted) qFatal("QThread: Destroyed while thread is still running"); d->data->thread.storeRelease(nullptr); @@ -514,7 +510,7 @@ bool QThread::isFinished() const { Q_D(const QThread); QMutexLocker locker(&d->mutex); - return d->finished || d->isInFinish; + return d->threadState >= QThreadPrivate::Finishing; } /*! @@ -527,7 +523,7 @@ bool QThread::isRunning() const { Q_D(const QThread); QMutexLocker locker(&d->mutex); - return d->running && !d->isInFinish; + return d->threadState == QThreadPrivate::Running; } /*! @@ -553,9 +549,9 @@ bool QThread::isRunning() const void QThread::setStackSize(uint stackSize) { Q_D(QThread); - QMutexLocker locker(&d->mutex); - Q_ASSERT_X(!d->running, "QThread::setStackSize", + Q_ASSERT_X(!isRunning(), "QThread::setStackSize", "cannot change stack size while the thread is running"); + QMutexLocker locker(&d->mutex); d->stackSize = stackSize; } @@ -769,7 +765,7 @@ void QThread::setPriority(Priority priority) } Q_D(QThread); QMutexLocker locker(&d->mutex); - if (!d->running) { + if (d->threadState != QThreadPrivate::Running) { qWarning("QThread::setPriority: Cannot set priority, thread is not running"); return; } @@ -1223,7 +1219,7 @@ void QThread::requestInterruption() return; } QMutexLocker locker(&d->mutex); - if (!d->running || d->finished || d->isInFinish) + if (d->threadState != QThreadPrivate::Running) return; d->interruptionRequested.store(true, std::memory_order_relaxed); } @@ -1262,7 +1258,7 @@ bool QThread::isInterruptionRequested() const return false; // slow path: if the flag is set, take into account run status: QMutexLocker locker(&d->mutex); - return d->running && !d->finished && !d->isInFinish; + return d->threadState == QThreadPrivate::Running; } /*! diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index d6fd99e5ba2..58c95cfab6f 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -184,16 +184,22 @@ public: mutable QMutex mutex; QAtomicInt quitLockRef; - bool running; - bool finished; - bool isInFinish; //when in QThreadPrivate::finish + enum State : quint8 { + // All state changes are imprecise + NotStarted = 0, // before start() or if failed to start + Running = 1, // in run() + Finishing = 2, // in QThreadPrivate::finish() + Finished = 3, // QThreadPrivate::finish() is done + }; + + State threadState = NotStarted; + bool exited = false; std::atomic interruptionRequested; - bool exited; - int returnCode; + int returnCode = -1; - uint stackSize; - std::underlying_type_t priority; + uint stackSize = 0; + std::underlying_type_t priority = QThread::InheritPriority; #ifdef Q_OS_UNIX QWaitCondition thread_done; @@ -226,7 +232,7 @@ public: void deref() { - if (!quitLockRef.deref() && running) { + if (!quitLockRef.deref() && threadState == Running) { QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit)); } } diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 22f0489c770..b5d37260c9a 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -95,7 +95,7 @@ static void destroy_current_thread_data(void *p) QThread *thread = data->thread.loadAcquire(); Q_ASSERT(thread); QThreadPrivate *thread_p = static_cast(QObjectPrivate::get(thread)); - Q_ASSERT(!thread_p->finished); + Q_ASSERT(thread_p->threadState == QThreadPrivate::Running); thread_p->finish(thread); } data->deref(); @@ -347,7 +347,7 @@ void QThreadPrivate::finish(void *arg) QMutexLocker locker(&d->mutex); - d->isInFinish = true; + d->threadState = QThreadPrivate::Finishing; d->priority = QThread::InheritPriority; void *data = &d->data->tls; locker.unlock(); @@ -366,11 +366,9 @@ void QThreadPrivate::finish(void *arg) locker.relock(); } - d->running = false; - d->finished = true; + d->threadState = QThreadPrivate::Finished; d->interruptionRequested.store(false, std::memory_order_relaxed); - d->isInFinish = false; d->data->threadId.storeRelaxed(nullptr); d->thread_done.wakeAll(); @@ -629,14 +627,13 @@ void QThread::start(Priority priority) Q_D(QThread); QMutexLocker locker(&d->mutex); - if (d->isInFinish) + if (d->threadState == QThreadPrivate::Finishing) d->thread_done.wait(locker.mutex()); - if (d->running) + if (d->threadState == QThreadPrivate::Running) return; - d->running = true; - d->finished = false; + d->threadState = QThreadPrivate::Running; d->returnCode = 0; d->exited = false; d->interruptionRequested.store(false, std::memory_order_relaxed); @@ -702,8 +699,7 @@ void QThread::start(Priority priority) // we failed to set the stacksize, and as the documentation states, // the thread will fail to run... - d->running = false; - d->finished = false; + d->threadState = QThreadPrivate::NotStarted; return; } } @@ -736,8 +732,7 @@ void QThread::start(Priority priority) if (code) { qErrnoWarning(code, "QThread::start: Thread creation error"); - d->running = false; - d->finished = false; + d->threadState = QThreadPrivate::NotStarted; d->data->threadId.storeRelaxed(nullptr); } } @@ -768,10 +763,10 @@ bool QThread::wait(QDeadlineTimer deadline) return false; } - if (d->finished || !d->running) + if (d->threadState == QThreadPrivate::NotStarted) return true; - while (d->running) { + while (d->threadState != QThreadPrivate::Finished) { if (!d->thread_done.wait(locker.mutex(), deadline)) return false; } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 0fba38d250b..3e1cc2c1aae 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -208,7 +208,7 @@ DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID) Q_ASSERT(thread); auto thread_p = static_cast(QObjectPrivate::get(thread)); Q_UNUSED(thread_p); - Q_ASSERT(!thread_p->finished); + Q_ASSERT(thread_p->threadState == QThreadPrivate::Running); QThreadPrivate::finish(thread); } data->deref(); @@ -290,7 +290,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept QThreadPrivate *d = thr->d_func(); QMutexLocker locker(lockAnyway ? &d->mutex : nullptr); - d->isInFinish = true; + d->threadState = QThreadPrivate::Finishing; d->priority = QThread::InheritPriority; void **tls_data = reinterpret_cast(&d->data->tls); if (lockAnyway) @@ -313,9 +313,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept locker.relock(); } - d->running = false; - d->finished = true; - d->isInFinish = false; + d->threadState = QThreadPrivate::Finished; d->interruptionRequested.store(false, std::memory_order_relaxed); if (!d->waiters) { @@ -377,20 +375,19 @@ void QThread::start(Priority priority) Q_D(QThread); QMutexLocker locker(&d->mutex); - if (d->isInFinish) { + if (d->threadState == QThreadPrivate::Finishing) { locker.unlock(); wait(); locker.relock(); } - if (d->running) + if (d->threadState == QThreadPrivate::Running) return; // avoid interacting with the binding system d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings() : QString(); - d->running = true; - d->finished = false; + d->threadState = QThreadPrivate::Running; d->exited = false; d->returnCode = 0; d->interruptionRequested.store(false, std::memory_order_relaxed); @@ -418,8 +415,7 @@ void QThread::start(Priority priority) if (!d->handle) { qErrnoWarning("QThread::start: Failed to create thread"); - d->running = false; - d->finished = true; + d->threadState = QThreadPrivate::NotStarted; return; } @@ -473,7 +469,7 @@ void QThread::terminate() { Q_D(QThread); QMutexLocker locker(&d->mutex); - if (!d->running) + if (d->threadState != QThreadPrivate::Running) return; if (!d->terminationEnabled) { d->terminatePending = true; @@ -493,7 +489,7 @@ bool QThread::wait(QDeadlineTimer deadline) qWarning("QThread::wait: Thread tried to wait on itself"); return false; } - if (d->finished || !d->running) + if (d->threadState == QThreadPrivate::NotStarted || d->threadState == QThreadPrivate::Finished) return true; ++d->waiters; @@ -516,13 +512,13 @@ bool QThread::wait(QDeadlineTimer deadline) locker.mutex()->lock(); --d->waiters; - if (ret && !d->finished) { + if (ret && d->threadState < QThreadPrivate::Finished) { // thread was terminated by someone else QThreadPrivate::finish(this, false); } - if (d->finished && !d->waiters) { + if (d->threadState == QThreadPrivate::Finished && !d->waiters) { CloseHandle(d->handle); d->handle = 0; }