src/corelib/concurrent/qfuturewatcher.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qfuturewatcher.h"
       
    43 
       
    44 #ifndef QT_NO_QFUTURE
       
    45 
       
    46 #include <QtCore/qcoreevent.h>
       
    47 #include <QtCore/qcoreapplication.h>
       
    48 #include <QtCore/qthread.h>
       
    49 
       
    50 #include "qfuturewatcher_p.h"
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 /*! \class QFutureWatcher
       
    55     \reentrant
       
    56     \since 4.4
       
    57 
       
    58     \ingroup thread
       
    59 
       
    60     \brief The QFutureWatcher class allows monitoring a QFuture using signals
       
    61     and slots.
       
    62 
       
    63     QFutureWatcher provides information and notifications about a QFuture. Use
       
    64     the setFuture() function to start watching a particular QFuture. The
       
    65     future() function returns the future set with setFuture().
       
    66 
       
    67     For convenience, several of QFuture's functions are also available in
       
    68     QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(),
       
    69     progressText(), isStarted(), isFinished(), isRunning(), isCanceled(),
       
    70     isPaused(), waitForFinished(), result(), and resultAt(). The cancel(),
       
    71     setPaused(), pause(), resume(), and togglePaused() functions are slots in
       
    72     QFutureWatcher.
       
    73 
       
    74     Status changes are reported via the started(), finished(), canceled(),
       
    75     paused(), resumed(), resultReadyAt(), and resultsReadyAt() signals.
       
    76     Progress information is provided from the progressRangeChanged(),
       
    77     void progressValueChanged(), and progressTextChanged() signals.
       
    78 
       
    79     Throttling control is provided by the setPendingResultsLimit() function.
       
    80     When the number of pending resultReadyAt() or resultsReadyAt() signals
       
    81     exceeds the limit, the computation represented by the future will be
       
    82     throttled automatically. The computation will resume once the number of
       
    83     pending signals drops below the limit.
       
    84 
       
    85     Example: Starting a computation and getting a slot callback when it's
       
    86     finished:
       
    87 
       
    88     \snippet doc/src/snippets/code/src_corelib_concurrent_qfuturewatcher.cpp 0
       
    89 
       
    90     Be aware that not all asynchronous computations can be canceled or paused.
       
    91     For example, the future returned by QtConcurrent::run() cannot be
       
    92     canceled; but the future returned by QtConcurrent::mappedReduced() can.
       
    93 
       
    94     QFutureWatcher<void> is specialized to not contain any of the result
       
    95     fetching functions. Any QFuture<T> can be watched by a
       
    96     QFutureWatcher<void> as well. This is useful if only status or progress
       
    97     information is needed; not the actual result data.
       
    98 
       
    99     \sa QFuture, {Concurrent Programming}{Qt Concurrent}
       
   100 */
       
   101 
       
   102 /*! \fn QFutureWatcher::QFutureWatcher(QObject *parent)
       
   103 
       
   104     Constructs a new QFutureWatcher with the given \a parent.
       
   105 */
       
   106 QFutureWatcherBase::QFutureWatcherBase(QObject *parent)
       
   107     :QObject(*new QFutureWatcherBasePrivate, parent)
       
   108 { }
       
   109 
       
   110 /*! \fn QFutureWatcher::~QFutureWatcher()
       
   111 
       
   112     Destroys the QFutureWatcher.
       
   113 */
       
   114 
       
   115 /*! \fn void QFutureWatcher::cancel()
       
   116 
       
   117     Cancels the asynchronous computation represented by the future(). Note that
       
   118     the cancelation is asynchronous. Use waitForFinished() after calling
       
   119     cancel() when you need synchronous cancelation.
       
   120 
       
   121     Currently available results may still be accessed on a canceled QFuture,
       
   122     but new results will \e not become available after calling this function.
       
   123     Also, this QFutureWatcher will not deliver progress and result ready
       
   124     signals once canceled. This includes the progressValueChanged(),
       
   125     progressRangeChanged(), progressTextChanged(), resultReadyAt(), and
       
   126     resultsReadyAt() signals.
       
   127 
       
   128     Be aware that not all asynchronous computations can be canceled. For
       
   129     example, the QFuture returned by QtConcurrent::run() cannot be canceled;
       
   130     but the QFuture returned by QtConcurrent::mappedReduced() can.
       
   131 */
       
   132 void QFutureWatcherBase::cancel()
       
   133 {
       
   134     futureInterface().cancel();
       
   135 }
       
   136 
       
   137 /*! \fn void QFutureWatcher::setPaused(bool paused)
       
   138 
       
   139     If \a paused is true, this function pauses the asynchronous computation
       
   140     represented by the future(). If the computation is already paused, this
       
   141     function does nothing. This QFutureWatcher will stop delivering progress
       
   142     and result ready signals while the future is paused. Signal delivery will
       
   143     continue once the computation is resumed.
       
   144 
       
   145     If \a paused is false, this function resumes the asynchronous computation.
       
   146     If the computation was not previously paused, this function does nothing.
       
   147 
       
   148     Be aware that not all computations can be paused. For example, the
       
   149     QFuture returned by QtConcurrent::run() cannot be paused; but the QFuture
       
   150     returned by QtConcurrent::mappedReduced() can.
       
   151 
       
   152     \sa pause(), resume(), togglePaused()
       
   153 */
       
   154 void QFutureWatcherBase::setPaused(bool paused)
       
   155 {
       
   156     futureInterface().setPaused(paused);
       
   157 }
       
   158 
       
   159 /*! \fn void QFutureWatcher::pause()
       
   160 
       
   161     Pauses the asynchronous computation represented by the future(). This is a
       
   162     convenience method that simply calls setPaused(true).
       
   163 
       
   164     \sa resume()
       
   165 */
       
   166 void QFutureWatcherBase::pause()
       
   167 {
       
   168     futureInterface().setPaused(true);
       
   169 }
       
   170 
       
   171 /*! \fn void QFutureWatcher::resume()
       
   172 
       
   173     Resumes the asynchronous computation represented by the future(). This is
       
   174     a convenience method that simply calls setPaused(false).
       
   175 
       
   176     \sa pause()
       
   177 */
       
   178 void QFutureWatcherBase::resume()
       
   179 {
       
   180     futureInterface().setPaused(false);
       
   181 }
       
   182 
       
   183 /*! \fn void QFutureWatcher::togglePaused()
       
   184 
       
   185     Toggles the paused state of the asynchronous computation. In other words,
       
   186     if the computation is currently paused, calling this function resumes it;
       
   187     if the computation is running, it becomes paused. This is a convenience
       
   188     method for calling setPaused(!isPaused()).
       
   189 
       
   190     \sa setPaused(), pause(), resume()
       
   191 */
       
   192 void QFutureWatcherBase::togglePaused()
       
   193 {
       
   194     futureInterface().togglePaused();
       
   195 }
       
   196 
       
   197 /*! \fn int QFutureWatcher::progressValue() const
       
   198 
       
   199     Returns the current progress value, which is between the progressMinimum()
       
   200     and progressMaximum().
       
   201 
       
   202     \sa progressMinimum(), progressMaximum()
       
   203 */
       
   204 int QFutureWatcherBase::progressValue() const
       
   205 {
       
   206     return futureInterface().progressValue();
       
   207 }
       
   208 
       
   209 /*! \fn int QFutureWatcher::progressMinimum() const
       
   210 
       
   211     Returns the minimum progressValue().
       
   212 
       
   213     \sa progressValue(), progressMaximum()
       
   214 */
       
   215 int QFutureWatcherBase::progressMinimum() const
       
   216 {
       
   217     return futureInterface().progressMinimum();
       
   218 }
       
   219 
       
   220 /*! \fn int QFutureWatcher::progressMaximum() const
       
   221 
       
   222     Returns the maximum progressValue().
       
   223 
       
   224     \sa progressValue(), progressMinimum()
       
   225 */
       
   226 int QFutureWatcherBase::progressMaximum() const
       
   227 {
       
   228     return futureInterface().progressMaximum();
       
   229 }
       
   230 
       
   231 /*! \fn QString QFutureWatcher::progressText() const
       
   232 
       
   233     Returns the (optional) textual representation of the progress as reported
       
   234     by the asynchronous computation.
       
   235 
       
   236     Be aware that not all computations provide a textual representation of the
       
   237     progress, and as such, this function may return an empty string.
       
   238 */
       
   239 QString QFutureWatcherBase::progressText() const
       
   240 {
       
   241     return futureInterface().progressText();
       
   242 }
       
   243 
       
   244 /*! \fn bool QFutureWatcher::isStarted() const
       
   245 
       
   246     Returns true if the asynchronous computation represented by the future()
       
   247     has been started; otherwise returns false.
       
   248 */
       
   249 bool QFutureWatcherBase::isStarted() const
       
   250 {
       
   251     return futureInterface().queryState(QFutureInterfaceBase::Started);
       
   252 }
       
   253 
       
   254 /*! \fn bool QFutureWatcher::isFinished() const
       
   255 
       
   256     Returns true if the asynchronous computation represented by the future()
       
   257     has finished; otherwise returns false.
       
   258 */
       
   259 bool QFutureWatcherBase::isFinished() const
       
   260 {
       
   261     Q_D(const QFutureWatcherBase);
       
   262     return d->finished;
       
   263 }
       
   264 
       
   265 /*! \fn bool QFutureWatcher::isRunning() const
       
   266 
       
   267     Returns true if the asynchronous computation represented by the future()
       
   268     is currently running; otherwise returns false.
       
   269 */
       
   270 bool QFutureWatcherBase::isRunning() const
       
   271 {
       
   272     return futureInterface().queryState(QFutureInterfaceBase::Running);
       
   273 }
       
   274 
       
   275 /*! \fn bool QFutureWatcher::isCanceled() const
       
   276 
       
   277     Returns true if the asynchronous computation has been canceled with the
       
   278     cancel() function; otherwise returns false.
       
   279 
       
   280     Be aware that the computation may still be running even though this
       
   281     function returns true. See cancel() for more details.
       
   282 */
       
   283 bool QFutureWatcherBase::isCanceled() const
       
   284 {
       
   285     return futureInterface().queryState(QFutureInterfaceBase::Canceled);
       
   286 }
       
   287 
       
   288 /*! \fn bool QFutureWatcher::isPaused() const
       
   289 
       
   290     Returns true if the asynchronous computation has been paused with the
       
   291     pause() function; otherwise returns false.
       
   292 
       
   293     Be aware that the computation may still be running even though this
       
   294     function returns true. See setPaused() for more details.
       
   295 
       
   296     \sa setPaused(), togglePaused()
       
   297 */
       
   298 bool QFutureWatcherBase::isPaused() const
       
   299 {
       
   300     return futureInterface().queryState(QFutureInterfaceBase::Paused);
       
   301 }
       
   302 
       
   303 /*! \fn void QFutureWatcher::waitForFinished()
       
   304 
       
   305     Waits for the asynchronous computation to finish (including cancel()ed
       
   306     computations).
       
   307 */
       
   308 void QFutureWatcherBase::waitForFinished()
       
   309 {
       
   310     futureInterface().waitForFinished();
       
   311 }
       
   312 
       
   313 /*! \fn void QFutureWatcher::setPendingResultsLimit(int limit)
       
   314 
       
   315     The setPendingResultsLimit() provides throttling control. When the number
       
   316     of pending resultReadyAt() or resultsReadyAt() signals exceeds the
       
   317     \a limit, the computation represented by the future will be throttled
       
   318     automatically. The computation will resume once the number of pending
       
   319     signals drops below the \a limit.
       
   320 */
       
   321 
       
   322 bool QFutureWatcherBase::event(QEvent *event)
       
   323 {
       
   324     Q_D(QFutureWatcherBase);
       
   325     if (event->type() == QEvent::FutureCallOut) {
       
   326         QFutureCallOutEvent *callOutEvent = static_cast<QFutureCallOutEvent *>(event);
       
   327 
       
   328         if (futureInterface().isPaused()) {
       
   329             d->pendingCallOutEvents.append(callOutEvent->clone());
       
   330             return true;
       
   331         }
       
   332 
       
   333         if (callOutEvent->callOutType == QFutureCallOutEvent::Resumed
       
   334             && !d->pendingCallOutEvents.isEmpty()) {
       
   335             // send the resume
       
   336             d->sendCallOutEvent(callOutEvent);
       
   337 
       
   338             // next send all pending call outs
       
   339             for (int i = 0; i < d->pendingCallOutEvents.count(); ++i)
       
   340                 d->sendCallOutEvent(d->pendingCallOutEvents.at(i));
       
   341             qDeleteAll(d->pendingCallOutEvents);
       
   342             d->pendingCallOutEvents.clear();
       
   343         } else {
       
   344             d->sendCallOutEvent(callOutEvent);
       
   345         }
       
   346         return true;
       
   347     }
       
   348     return QObject::event(event);
       
   349 }
       
   350 
       
   351 void QFutureWatcherBase::setPendingResultsLimit(int limit)
       
   352 {
       
   353     Q_D(QFutureWatcherBase);
       
   354     d->maximumPendingResultsReady = limit;
       
   355 }
       
   356 
       
   357 void QFutureWatcherBase::connectNotify(const char * signal)
       
   358 {
       
   359     Q_D(QFutureWatcherBase);
       
   360     if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0)
       
   361         d->resultAtConnected.ref();
       
   362 }
       
   363 
       
   364 void QFutureWatcherBase::disconnectNotify(const char * signal)
       
   365 {
       
   366     Q_D(QFutureWatcherBase);
       
   367     if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0)
       
   368         d->resultAtConnected.deref();
       
   369 }
       
   370 
       
   371 /*!
       
   372     \internal
       
   373 */
       
   374 QFutureWatcherBasePrivate::QFutureWatcherBasePrivate()
       
   375     : maximumPendingResultsReady(QThread::idealThreadCount() * 2),
       
   376       resultAtConnected(0)
       
   377 { }
       
   378 
       
   379 /*!
       
   380     \internal
       
   381 */
       
   382 void QFutureWatcherBase::connectOutputInterface()
       
   383 {
       
   384     futureInterface().d->connectOutputInterface(d_func());
       
   385 }
       
   386 
       
   387 /*!
       
   388     \internal
       
   389 */
       
   390 void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment)
       
   391 {
       
   392     if (pendingAssignment) {
       
   393         Q_D(QFutureWatcherBase);
       
   394         d->pendingResultsReady = 0;
       
   395         qDeleteAll(d->pendingCallOutEvents);
       
   396         d->pendingCallOutEvents.clear();
       
   397         d->finished = false;
       
   398     }
       
   399 
       
   400     futureInterface().d->disconnectOutputInterface(d_func());
       
   401 }
       
   402 
       
   403 void QFutureWatcherBasePrivate::postCallOutEvent(const QFutureCallOutEvent &callOutEvent)
       
   404 {
       
   405     Q_Q(QFutureWatcherBase);
       
   406 
       
   407     if (callOutEvent.callOutType == QFutureCallOutEvent::ResultsReady) {
       
   408         if (pendingResultsReady.fetchAndAddRelaxed(1) >= maximumPendingResultsReady)
       
   409             q->futureInterface().d->internal_setThrottled(true);
       
   410     }
       
   411 
       
   412     QCoreApplication::postEvent(q, callOutEvent.clone());
       
   413 }
       
   414 
       
   415 void QFutureWatcherBasePrivate::callOutInterfaceDisconnected()
       
   416 {
       
   417     QCoreApplication::removePostedEvents(q_func(), QEvent::FutureCallOut);
       
   418 }
       
   419 
       
   420 void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
       
   421 {
       
   422     Q_Q(QFutureWatcherBase);
       
   423 
       
   424     switch (event->callOutType) {
       
   425         case QFutureCallOutEvent::Started:
       
   426             emit q->started();
       
   427         break;
       
   428         case QFutureCallOutEvent::Finished:
       
   429             finished = true;
       
   430             emit q->finished();
       
   431         break;
       
   432         case QFutureCallOutEvent::Canceled:
       
   433             pendingResultsReady = 0;
       
   434             emit q->canceled();
       
   435         break;
       
   436         case QFutureCallOutEvent::Paused:
       
   437             if (q->futureInterface().isCanceled())
       
   438                 break;
       
   439             emit q->paused();
       
   440         break;
       
   441         case QFutureCallOutEvent::Resumed:
       
   442             if (q->futureInterface().isCanceled())
       
   443                 break;
       
   444             emit q->resumed();
       
   445         break;
       
   446         case QFutureCallOutEvent::ResultsReady: {
       
   447             if (q->futureInterface().isCanceled())
       
   448                 break;
       
   449 
       
   450             if (pendingResultsReady.fetchAndAddRelaxed(-1) <= maximumPendingResultsReady)
       
   451                 q->futureInterface().setThrottled(false);
       
   452 
       
   453             const int beginIndex = event->index1;
       
   454             const int endIndex = event->index2;
       
   455 
       
   456             emit q->resultsReadyAt(beginIndex, endIndex);
       
   457 
       
   458             if (int(resultAtConnected) <= 0)
       
   459                 break;
       
   460 
       
   461             for (int i = beginIndex; i < endIndex; ++i)
       
   462                 emit q->resultReadyAt(i);
       
   463 
       
   464         } break;
       
   465         case QFutureCallOutEvent::Progress:
       
   466             if (q->futureInterface().isCanceled())
       
   467                 break;
       
   468 
       
   469             emit q->progressValueChanged(event->index1);
       
   470             if (!event->text.isNull()) // ###
       
   471                 q->progressTextChanged(event->text);
       
   472         break;
       
   473         case QFutureCallOutEvent::ProgressRange:
       
   474             emit q->progressRangeChanged(event->index1, event->index2);
       
   475         break;
       
   476         default: break;
       
   477     }
       
   478 }
       
   479 
       
   480 
       
   481 /*! \fn const T &QFutureWatcher::result() const
       
   482 
       
   483     Returns the first result in the future(). If the result is not immediately
       
   484     available, this function will block and wait for the result to become
       
   485     available. This is a convenience method for calling resultAt(0).
       
   486 
       
   487     \sa resultAt()
       
   488 */
       
   489 
       
   490 /*! \fn const T &QFutureWatcher::resultAt(int index) const
       
   491 
       
   492     Returns the result at \a index in the future(). If the result is not
       
   493     immediately available, this function will block and wait for the result to
       
   494     become available.
       
   495 
       
   496     \sa result()
       
   497 */
       
   498 
       
   499 /*! \fn void QFutureWatcher::setFuture(const QFuture<T> &future)
       
   500 
       
   501     Starts watching the given \a future.
       
   502 */
       
   503 
       
   504 /*! \fn QFuture<T> QFutureWatcher::future() const
       
   505 
       
   506     Returns the watched future.
       
   507 */
       
   508 
       
   509 /*! \fn void QFutureWatcher::started()
       
   510 
       
   511     This signal is emitted when this QFutureWatcher starts watching the future
       
   512     set with setFuture().
       
   513 */
       
   514 
       
   515 /*!
       
   516     \fn void QFutureWatcher::finished()
       
   517     This signal is emitted when the watched future finishes.
       
   518 */
       
   519 
       
   520 /*!
       
   521     \fn void QFutureWatcher::canceled()
       
   522     This signal is emitted if the watched future is canceled.
       
   523 */
       
   524 
       
   525 /*! \fn void QFutureWatcher::paused()
       
   526     This signal is emitted when the watched future is paused.
       
   527 */
       
   528 
       
   529 /*! \fn void QFutureWatcher::resumed()
       
   530     This signal is emitted when the watched future is resumed.
       
   531 */
       
   532 
       
   533 /*!
       
   534     \fn void QFutureWatcher::progressRangeChanged(int minimum, int maximum)
       
   535 
       
   536     The progress range for the watched future has changed to \a minimum and
       
   537     \a maximum
       
   538 */
       
   539 
       
   540 /*!
       
   541     \fn void QFutureWatcher::progressValueChanged(int progressValue)
       
   542 
       
   543     This signal is emitted when the watched future reports progress,
       
   544     \a progressValue gives the current progress. In order to avoid overloading
       
   545     the GUI event loop, QFutureWatcher limits the progress signal emission
       
   546     rate. This means that listeners connected to this slot might not get all
       
   547     progress reports the future makes. The last progress update (where
       
   548     \a progressValue equals the maximum value) will always be delivered.
       
   549 */
       
   550 
       
   551 /*! \fn void QFutureWatcher::progressTextChanged(const QString &progressText)
       
   552 
       
   553     This signal is emitted when the watched future reports textual progress
       
   554     information, \a progressText.
       
   555 */
       
   556 
       
   557 /*!
       
   558     \fn void QFutureWatcher::resultReadyAt(int index)
       
   559 
       
   560     This signal is emitted when the watched future reports a ready result at
       
   561     \a index. If the future reports multiple results, the index will indicate
       
   562     which one it is. Results can be reported out-of-order. To get the result,
       
   563     call future().result(index);
       
   564 */
       
   565 
       
   566 /*!
       
   567     \fn void QFutureWatcher::resultsReadyAt(int beginIndex, int endIndex);
       
   568 
       
   569     This signal is emitted when the watched future reports ready results.
       
   570     The results are indexed from \a beginIndex to \a endIndex.
       
   571 
       
   572 */
       
   573 
       
   574 QT_END_NAMESPACE
       
   575 
       
   576 #endif // QT_NO_CONCURRENT