diff options
author | Morten Sørvig <msorvig@trolltech.com> | 2009-06-24 13:20:02 (GMT) |
---|---|---|
committer | Morten Sørvig <msorvig@trolltech.com> | 2009-06-24 13:20:02 (GMT) |
commit | 055c9c41b3f659cbbf758d15e8350c5dd2b5faa1 (patch) | |
tree | 5af9cb79b057ab34bc9ace88c86a695a477dfba6 | |
parent | 17c96dec2a16db0994df7980d511dbff83a5041d (diff) | |
download | Qt-055c9c41b3f659cbbf758d15e8350c5dd2b5faa1.zip Qt-055c9c41b3f659cbbf758d15e8350c5dd2b5faa1.tar.gz Qt-055c9c41b3f659cbbf758d15e8350c5dd2b5faa1.tar.bz2 |
Improve QtConcurrent scalability.
Reduce lock contention QtConcurrent by swiching the ThreadEngineSemaphore
class over to a QAtomic-based implementation.
-rw-r--r-- | src/corelib/concurrent/qtconcurrentthreadengine.h | 86 |
1 files changed, 62 insertions, 24 deletions
diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.h b/src/corelib/concurrent/qtconcurrentthreadengine.h index 6f1c7e7..21a3a28 100644 --- a/src/corelib/concurrent/qtconcurrentthreadengine.h +++ b/src/corelib/concurrent/qtconcurrentthreadengine.h @@ -51,6 +51,8 @@ #include <QtCore/qdebug.h> #include <QtCore/qtconcurrentexception.h> #include <QtCore/qwaitcondition.h> +#include <QtCore/qatomic.h> +#include <QtCore/qsemaphore.h> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -61,55 +63,91 @@ QT_MODULE(Core) namespace QtConcurrent { -// A Semaphore that can wait until all resources are returned. +// The ThreadEngineSemaphore counts worker threads, and allows one +// thread to wait for all others to finish. Tested for its use in +// QtConcurrent, requires more testing for use as a general class. class ThreadEngineSemaphore { +private: + // The thread count is maintained as an integer in the count atomic + // variable. The count can be either positive or negative - a negative + // count signals that a thread is waiting on the semaphore. + QAtomicInt count; + QSemaphore semaphore; public: ThreadEngineSemaphore() :count(0) { } void acquire() { - QMutexLocker lock(&mutex); - ++count; + forever { + int localCount = int(count); + if (localCount < 0) { + if (count.testAndSetOrdered(localCount, localCount -1)) + return; + } else { + if (count.testAndSetOrdered(localCount, localCount + 1)) + return; + } + } } int release() { - QMutexLocker lock(&mutex); - if (--count == 0) - waitCondition.wakeAll(); - return count; + forever { + int localCount = int(count); + if (localCount == -1) { + if (count.testAndSetOrdered(-1, 0)) { + semaphore.release(); + return 0; + } + } else if (localCount < 0) { + if (count.testAndSetOrdered(localCount, localCount + 1)) + return qAbs(localCount + 1); + } else { + if (count.testAndSetOrdered(localCount, localCount - 1)) + return localCount - 1; + } + } } - // Wait until all resources are released. + // Wait until all threads have been released void wait() { - QMutexLocker lock(&mutex); - if (count != 0) - waitCondition.wait(&mutex); + forever { + int localCount = int(count); + if (localCount == 0) + return; + + if (count.testAndSetOrdered(localCount, -localCount)) { + semaphore.acquire(); + return; + } + } } int currentCount() { - return count; + return int(count); } - // releases a resource, unless this is the last resource. - // returns true if a resource was released. + // releases a thread, unless this is the last thread. + // returns true if the thread was released. bool releaseUnlessLast() { - QMutexLocker lock(&mutex); - if (count == 1) - return false; - --count; - return true; + forever { + int localCount = int(count); + if (qAbs(localCount) == 1) { + return false; + } else if (localCount < 0) { + if (count.testAndSetOrdered(localCount, localCount + 1)) + return true; + } else { + if (count.testAndSetOrdered(localCount, localCount - 1)) + return true; + } + } } - -private: - QMutex mutex; - int count; - QWaitCondition waitCondition; }; enum ThreadFunctionResult { ThrottleThread, ThreadFinished }; |