diff options
Diffstat (limited to 'src/corelib/thread')
-rw-r--r-- | src/corelib/thread/qbasicatomic.h | 6 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface.cpp | 2 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface_p.h | 1 | ||||
-rw-r--r-- | src/corelib/thread/qmutex.cpp | 15 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_linux.cpp | 26 | ||||
-rw-r--r-- | src/corelib/thread/qthread.cpp | 60 | ||||
-rw-r--r-- | src/corelib/thread/qthread.h | 3 | ||||
-rw-r--r-- | src/corelib/thread/qthread_p.h | 1 | ||||
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 2 | ||||
-rw-r--r-- | src/corelib/thread/qthread_win.cpp | 2 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool.cpp | 65 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool.h | 2 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool_p.h | 1 | ||||
-rw-r--r-- | src/corelib/thread/qwaitcondition_unix.cpp | 2 |
14 files changed, 139 insertions, 49 deletions
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index cf0a6a55e4..ddcc25f7b7 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -60,11 +60,11 @@ // Processor dependent implementation #elif defined(Q_PROCESSOR_ALPHA) # include "QtCore/qatomic_alpha.h" -#elif defined(Q_PROCESSOR_ARM_V7) +#elif defined(Q_PROCESSOR_ARM_V7) && defined(Q_PROCESSOR_ARM_32) # include "QtCore/qatomic_armv7.h" -#elif defined(Q_PROCESSOR_ARM_V6) +#elif defined(Q_PROCESSOR_ARM_V6) && defined(Q_PROCESSOR_ARM_32) # include "QtCore/qatomic_armv6.h" -#elif defined(Q_PROCESSOR_ARM_V5) +#elif defined(Q_PROCESSOR_ARM_V5) && defined(Q_PROCESSOR_ARM_32) # include "QtCore/qatomic_armv5.h" #elif defined(Q_PROCESSOR_BFIN) # include "QtCore/qatomic_bfin.h" diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index 0f7d04a7c5..2a79a501e3 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -432,7 +432,7 @@ bool QFutureInterfaceBase::derefT() const QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), - state(initialState), pendingResults(0), + state(initialState), manualProgress(false), m_expectedResultCount(0), runnable(0) { progressTime.invalidate(); diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h index a638fbeaa6..8b38ebfc66 100644 --- a/src/corelib/thread/qfutureinterface_p.h +++ b/src/corelib/thread/qfutureinterface_p.h @@ -163,7 +163,6 @@ public: QFutureInterfaceBase::State state; QElapsedTimer progressTime; QWaitCondition pausedWaitCondition; - int pendingResults; QtPrivate::ResultStoreBase m_results; bool manualProgress; int m_expectedResultCount; diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 378813c889..ed84504a58 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -50,6 +50,7 @@ #include "qelapsedtimer.h" #include "qthread.h" #include "qmutex_p.h" +#include "qtypetraits.h" #ifndef QT_LINUX_FUTEX #include "private/qfreelist_p.h" @@ -75,8 +76,14 @@ class QRecursiveMutexPrivate : public QMutexData public: QRecursiveMutexPrivate() : QMutexData(QMutex::Recursive), owner(0), count(0) {} - Qt::HANDLE owner; + + // written to by the thread that first owns 'mutex'; + // read during attempts to acquire ownership of 'mutex' from any other thread: + QAtomicPointer<QtPrivate::remove_pointer<Qt::HANDLE>::type> owner; + + // only ever accessed from the thread that owns 'mutex': uint count; + QMutex mutex; bool lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT; @@ -611,7 +618,7 @@ void QMutexPrivate::derefWaiters(int value) Q_DECL_NOTHROW inline bool QRecursiveMutexPrivate::lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT { Qt::HANDLE self = QThread::currentThreadId(); - if (owner == self) { + if (owner.load() == self) { ++count; Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter"); return true; @@ -624,7 +631,7 @@ inline bool QRecursiveMutexPrivate::lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT } if (success) - owner = self; + owner.store(self); return success; } @@ -636,7 +643,7 @@ inline void QRecursiveMutexPrivate::unlock() Q_DECL_NOTHROW if (count > 0) { count--; } else { - owner = 0; + owner.store(0); mutex.QBasicMutex::unlock(); } } diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index 24d89030d1..18aedfbf75 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -54,21 +54,6 @@ #include <errno.h> #include <asm/unistd.h> -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -// C++11 mode -# include <type_traits> - -static void checkElapsedTimerIsTrivial() -{ - Q_STATIC_ASSERT(std::has_trivial_default_constructor<QT_PREPEND_NAMESPACE(QElapsedTimer)>::value); -} - -#else -static void checkElapsedTimerIsTrivial() -{ -} -#endif - #ifndef QT_LINUX_FUTEX # error "Qt build is broken: qmutex_linux.cpp is being built but futex support is not wanted" #endif @@ -175,7 +160,7 @@ static inline QMutexData *dummyFutexValue() } template <bool IsTimed> static inline -bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = -1) Q_DECL_NOTHROW +bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = -1, QElapsedTimer *elapsedTimer = 0) Q_DECL_NOTHROW { if (!IsTimed) timeout = -1; @@ -185,12 +170,9 @@ bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = - return false; struct timespec ts, *pts = 0; - QElapsedTimer elapsedTimer; - checkElapsedTimerIsTrivial(); if (IsTimed && timeout > 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000 * 1000; - elapsedTimer.start(); } // the mutex is locked already, set a bit indicating we're waiting @@ -198,7 +180,7 @@ bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = - if (IsTimed && pts == &ts) { // recalculate the timeout qint64 xtimeout = qint64(timeout) * 1000 * 1000; - xtimeout -= elapsedTimer.nsecsElapsed(); + xtimeout -= elapsedTimer->nsecsElapsed(); if (xtimeout <= 0) { // timer expired after we returned return false; @@ -232,7 +214,9 @@ void QBasicMutex::lockInternal() Q_DECL_NOTHROW bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW { Q_ASSERT(!isRecursive()); - return lockInternal_helper<true>(d_ptr, timeout); + QElapsedTimer elapsedTimer; + elapsedTimer.start(); + return lockInternal_helper<true>(d_ptr, timeout, &elapsedTimer); } void QBasicMutex::unlockInternal() Q_DECL_NOTHROW diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 4d5bee3154..35d57b3d83 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -146,7 +146,8 @@ void QAdoptedThread::run() QThreadPrivate::QThreadPrivate(QThreadData *d) : QObjectPrivate(), running(false), finished(false), - isInFinish(false), exited(false), returnCode(-1), + isInFinish(false), interruptionRequested(false), + exited(false), returnCode(-1), stackSize(0), priority(QThread::InheritPriority), data(d) { #if defined (Q_OS_UNIX) @@ -801,4 +802,61 @@ bool QThread::event(QEvent *event) } } +/*! + \since 5.2 + + Request the interruption of the thread. + That request is advisory and it is up to code running on the thread to decide + if and how it should act upon such request. + This function does not stop any event loop running on the thread and + does not terminate it in any way. + + \sa isInterruptionRequested() +*/ + +void QThread::requestInterruption() +{ + Q_D(QThread); + QMutexLocker locker(&d->mutex); + if (!d->running || d->finished || d->isInFinish) + return; + if (this == QCoreApplicationPrivate::theMainThread) { + qWarning("QThread::requestInterruption has no effect on the main thread"); + return; + } + d->interruptionRequested = true; +} + +/*! + \since 5.2 + + Return true if the task running on this thread should be stopped. + An interruption can be requested by requestInterruption(). + + This function can be used to make long running tasks cleanly interruptible. + Never checking or acting on the value returned by this function is safe, + however it is advisable do so regularly in long running functions. + Take care not to call it too often, to keep the overhead low. + + \code + void long_task() { + forever { + if ( QThread::currentThread()->isInterruptionRequested() ) { + return; + } + } + } + \endcode + + \sa currentThread() requestInterruption() +*/ +bool QThread::isInterruptionRequested() const +{ + Q_D(const QThread); + QMutexLocker locker(&d->mutex); + if (!d->running || d->finished || d->isInFinish) + return false; + return d->interruptionRequested; +} + QT_END_NAMESPACE diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 19c0f82d86..f06981c0bd 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -86,6 +86,9 @@ public: bool isFinished() const; bool isRunning() const; + void requestInterruption(); + bool isInterruptionRequested() const; + void setStackSize(uint stackSize); uint stackSize() const; diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 9d773b3c1c..5e4eedaac7 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -150,6 +150,7 @@ public: bool running; bool finished; bool isInFinish; //when in QThreadPrivate::finish + bool interruptionRequested; bool exited; int returnCode; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 6a91193785..15558cb148 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -377,6 +377,7 @@ void QThreadPrivate::finish(void *arg) d->thread_id = 0; d->running = false; d->finished = true; + d->interruptionRequested = false; d->isInFinish = false; d->thread_done.wakeAll(); @@ -549,6 +550,7 @@ void QThread::start(Priority priority) d->finished = false; d->returnCode = 0; d->exited = false; + d->interruptionRequested = false; pthread_attr_t attr; pthread_attr_init(&attr); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index a0fac8eff2..d49a6a9a8e 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -377,6 +377,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) d->running = false; d->finished = true; d->isInFinish = false; + d->interruptionRequested = false; if (!d->waiters) { CloseHandle(d->handle); @@ -446,6 +447,7 @@ void QThread::start(Priority priority) d->finished = false; d->exited = false; d->returnCode = 0; + d->interruptionRequested = false; /* NOTE: we create the thread in the suspended state, set the diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index a7d52f9652..9ef40a5209 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -52,14 +52,14 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QThreadPool, theInstance) /* - QThread wrapper, provides synchronizitaion against a ThreadPool + QThread wrapper, provides synchronization against a ThreadPool */ class QThreadPoolThread : public QThread { public: QThreadPoolThread(QThreadPoolPrivate *manager); void run(); - void registerTheadInactive(); + void registerThreadInactive(); QThreadPoolPrivate *manager; QRunnable *runnable; @@ -103,7 +103,7 @@ void QThreadPoolThread::run() qWarning("Qt Concurrent has caught an exception thrown from a worker thread.\n" "This is not supported, exceptions thrown in worker threads must be\n" "caught before control returns to Qt Concurrent."); - registerTheadInactive(); + registerThreadInactive(); throw; } #endif @@ -121,7 +121,7 @@ void QThreadPoolThread::run() } while (r != 0); if (manager->isExiting) { - registerTheadInactive(); + registerThreadInactive(); break; } @@ -129,7 +129,7 @@ void QThreadPoolThread::run() bool expired = manager->tooManyThreadsActive(); if (!expired) { ++manager->waitingThreads; - registerTheadInactive(); + registerThreadInactive(); // wait for work, exiting after the expiry timeout is reached expired = !manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout); ++manager->activeThreads; @@ -139,13 +139,13 @@ void QThreadPoolThread::run() } if (expired) { manager->expiredThreads.enqueue(this); - registerTheadInactive(); + registerThreadInactive(); break; } } } -void QThreadPoolThread::registerTheadInactive() +void QThreadPoolThread::registerThreadInactive() { if (--manager->activeThreads == 0) manager->noActiveThreads.wakeAll(); @@ -180,6 +180,7 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) // recycle an available thread --waitingThreads; enqueueTask(task); + runnableReady.wakeOne(); return true; } @@ -218,13 +219,10 @@ void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) if (it != begin && priority > (*(it - 1)).second) it = std::upper_bound(begin, --it, priority); queue.insert(it - begin, qMakePair(runnable, priority)); - runnableReady.wakeOne(); } int QThreadPoolPrivate::activeThreadCount() const { - // To improve scalability this function is called without holding - // the mutex lock -- keep it thread-safe. return (allThreads.count() - expiredThreads.count() - waitingThreads @@ -262,7 +260,7 @@ void QThreadPoolPrivate::startThread(QRunnable *runnable) /*! \internal - Makes all threads exit, waits for each tread to exit and deletes it. + Makes all threads exit, waits for each thread to exit and deletes it. */ void QThreadPoolPrivate::reset() { @@ -308,10 +306,22 @@ bool QThreadPoolPrivate::waitForDone(int msecs) return queue.isEmpty() && activeThreads == 0; } +void QThreadPoolPrivate::clear() +{ + QMutexLocker locker(&mutex); + for (QList<QPair<QRunnable *, int> >::const_iterator it = queue.constBegin(); + it != queue.constEnd(); ++it) { + QRunnable* r = it->first; + if (r->autoDelete() && !--r->ref) + delete r; + } + queue.clear(); +} + /*! \internal - Seaches for \a runnable in the queue, removes it from the queue and - runs it if found. This functon does not return until the runnable + Searches for \a runnable in the queue, removes it from the queue and + runs it if found. This function does not return until the runnable has completed. */ void QThreadPoolPrivate::stealRunnable(QRunnable *runnable) @@ -446,8 +456,14 @@ void QThreadPool::start(QRunnable *runnable, int priority) Q_D(QThreadPool); QMutexLocker locker(&d->mutex); - if (!d->tryStart(runnable)) + if (!d->tryStart(runnable)) { d->enqueueTask(runnable, priority); + + if (d->waitingThreads > 0) { + --d->waitingThreads; + d->runnableReady.wakeOne(); + } + } } /*! @@ -473,12 +489,11 @@ bool QThreadPool::tryStart(QRunnable *runnable) Q_D(QThreadPool); - // To improve scalability perform a check on the thread count - // before locking the mutex. + QMutexLocker locker(&d->mutex); + if (d->allThreads.isEmpty() == false && d->activeThreadCount() >= d->maxThreadCount) return false; - QMutexLocker locker(&d->mutex); return d->tryStart(runnable); } @@ -552,6 +567,7 @@ void QThreadPool::setMaxThreadCount(int maxThreadCount) int QThreadPool::activeThreadCount() const { Q_D(const QThreadPool); + QMutexLocker locker(&d->mutex); return d->activeThreadCount(); } @@ -609,6 +625,21 @@ bool QThreadPool::waitForDone(int msecs) return rc; } +/*! + \since 5.2 + + Removes the runnables that are not yet started from the queue. + The runnables for which \l{QRunnable::autoDelete()}{runnable->autoDelete()} + returns true are deleted. + + \sa start() +*/ +void QThreadPool::clear() +{ + Q_D(QThreadPool); + d->clear(); +} + QT_END_NAMESPACE #endif diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h index ffc16dedbe..22a42c2272 100644 --- a/src/corelib/thread/qthreadpool.h +++ b/src/corelib/thread/qthreadpool.h @@ -83,6 +83,8 @@ public: void releaseThread(); bool waitForDone(int msecs = -1); + + void clear(); }; QT_END_NAMESPACE diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index 754d754e74..ba77f7e57c 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -83,6 +83,7 @@ public: void startThread(QRunnable *runnable = 0); void reset(); bool waitForDone(int msecs); + void clear(); void stealRunnable(QRunnable *); mutable QMutex mutex; diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index 616a4bdfb8..e8322959ca 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -136,7 +136,7 @@ public: code = pthread_cond_wait(&cond, &mutex); } if (code == 0 && wakeups == 0) { - // many vendors warn of spurios wakeups from + // many vendors warn of spurious wakeups from // pthread_cond_wait(), especially after signal delivery, // even though POSIX doesn't allow for it... sigh continue; |