summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread')
-rw-r--r--src/corelib/thread/qbasicatomic.h6
-rw-r--r--src/corelib/thread/qfutureinterface.cpp2
-rw-r--r--src/corelib/thread/qfutureinterface_p.h1
-rw-r--r--src/corelib/thread/qmutex.cpp15
-rw-r--r--src/corelib/thread/qmutex_linux.cpp26
-rw-r--r--src/corelib/thread/qthread.cpp60
-rw-r--r--src/corelib/thread/qthread.h3
-rw-r--r--src/corelib/thread/qthread_p.h1
-rw-r--r--src/corelib/thread/qthread_unix.cpp2
-rw-r--r--src/corelib/thread/qthread_win.cpp2
-rw-r--r--src/corelib/thread/qthreadpool.cpp65
-rw-r--r--src/corelib/thread/qthreadpool.h2
-rw-r--r--src/corelib/thread/qthreadpool_p.h1
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp2
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;