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