source: trunk/src/corelib/concurrent/qfuturewatcher.cpp@ 181

Last change on this file since 181 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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