diff -r 000000000000 -r 1918ee327afb src/corelib/concurrent/qtconcurrentthreadengine.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/corelib/concurrent/qtconcurrentthreadengine.h Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_THREADENGINE_H +#define QTCONCURRENT_THREADENGINE_H + +#include + +#ifndef QT_NO_CONCURRENT + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +// The ThreadEngineBarrier 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 ThreadEngineBarrier +{ +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 barrier. + + // BC note: inlined code from Qt < 4.6 will expect to find the QMutex + // and QAtomicInt here. ### Qt 5: remove. + QMutex mutex; + QAtomicInt count; + + QSemaphore semaphore; +public: + ThreadEngineBarrier(); + void acquire(); + int release(); + void wait(); + int currentCount(); + bool releaseUnlessLast(); +}; + +enum ThreadFunctionResult { ThrottleThread, ThreadFinished }; + +// The ThreadEngine controls the threads used in the computation. +// Can be run in three modes: single threaded, multi-threaded blocking +// and multi-threaded asynchronous. +// The code for the single threaded mode is +class Q_CORE_EXPORT ThreadEngineBase: public QRunnable +{ +public: + // Public API: + ThreadEngineBase(); + virtual ~ThreadEngineBase(); + void startSingleThreaded(); + void startBlocking(); + void startThread(); + bool isCanceled(); + void waitForResume(); + bool isProgressReportingEnabled(); + void setProgressValue(int progress); + void setProgressRange(int minimum, int maximum); + void acquireBarrierSemaphore(); + +protected: // The user overrides these: + virtual void start() {} + virtual void finish() {} + virtual ThreadFunctionResult threadFunction() { return ThreadFinished; } + virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; } + virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; } +private: + bool startThreadInternal(); + void startThreads(); + void threadExit(); + bool threadThrottleExit(); + void run(); + virtual void asynchronousFinish() = 0; +#ifndef QT_NO_EXCEPTIONS + void handleException(const QtConcurrent::Exception &exception); +#endif +protected: + QFutureInterfaceBase *futureInterface; + QThreadPool *threadPool; + ThreadEngineBarrier barrier; + QtConcurrent::internal::ExceptionStore exceptionStore; +}; + + +template +class ThreadEngine : public virtual ThreadEngineBase +{ +public: + typedef T ResultType; + + virtual T *result() { return 0; } + + QFutureInterface *futureInterfaceTyped() + { + return static_cast *>(futureInterface); + } + + // Runs the user algorithm using a single thread. + T *startSingleThreaded() + { + ThreadEngineBase::startSingleThreaded(); + return result(); + } + + // Runs the user algorithm using multiple threads. + // This function blocks until the algorithm is finished, + // and then returns the result. + T *startBlocking() + { + ThreadEngineBase::startBlocking(); + return result(); + } + + // Runs the user algorithm using multiple threads. + // Does not block, returns a future. + QFuture startAsynchronously() + { + futureInterface = new QFutureInterface(); + + // reportStart() must be called before starting threads, otherwise the + // user algorithm might finish while reportStart() is running, which + // is very bad. + futureInterface->reportStarted(); + QFuture future = QFuture(futureInterfaceTyped()); + start(); + + acquireBarrierSemaphore(); + threadPool->start(this); + return future; + } + + void asynchronousFinish() + { + finish(); + futureInterfaceTyped()->reportFinished(result()); + delete futureInterfaceTyped(); + delete this; + } + + + void reportResult(const T *_result, int index = -1) + { + if (futureInterface) + futureInterfaceTyped()->reportResult(_result, index); + } + + void reportResults(const QVector &_result, int index = -1, int count = -1) + { + if (futureInterface) + futureInterfaceTyped()->reportResults(_result, index, count); + } +}; + +// The ThreadEngineStarter class ecapsulates the return type +// from the thread engine. +// Depending on how the it is used, it will run +// the engine in either blocking mode or asynchronous mode. +template +class ThreadEngineStarterBase +{ +public: + ThreadEngineStarterBase(ThreadEngine *_threadEngine) + : threadEngine(_threadEngine) { } + + inline ThreadEngineStarterBase(const ThreadEngineStarterBase &other) + : threadEngine(other.threadEngine) { } + + QFuture startAsynchronously() + { + return threadEngine->startAsynchronously(); + } + + operator QFuture() + { + return startAsynchronously(); + } + +protected: + ThreadEngine *threadEngine; +}; + + +// We need to factor out the code that dereferences the T pointer, +// with a specialization where T is void. (code that dereferences a void * +// won't compile) +template +class ThreadEngineStarter : public ThreadEngineStarterBase +{ + typedef ThreadEngineStarterBase Base; + typedef ThreadEngine TypedThreadEngine; +public: + ThreadEngineStarter(TypedThreadEngine *eng) + : Base(eng) { } + + T startBlocking() + { + T t = *this->threadEngine->startBlocking(); + delete this->threadEngine; + return t; + } +}; + +// Full template specialization where T is void. +template <> +class ThreadEngineStarter : public ThreadEngineStarterBase +{ +public: + ThreadEngineStarter(ThreadEngine *_threadEngine) + :ThreadEngineStarterBase(_threadEngine) {} + + void startBlocking() + { + this->threadEngine->startBlocking(); + delete this->threadEngine; + } +}; + +template +inline ThreadEngineStarter startThreadEngine(ThreadEngine *threadEngine) +{ + return ThreadEngineStarter(threadEngine); +} + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif