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

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