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

source code of qtbase/src/corelib/thread/qfuturewatcher.cpp