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