QGIS API Documentation 4.3.0-Master (8c22baaae17)
Loading...
Searching...
No Matches
qgsfutureutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsthreadingutils.h
3 --------------------------------------
4 Date : August 2026
5 Copyright : (C) 2026 by David Koňařík
6 email : dvdkon at konarici dot cz
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsfutureutils.h"
17
18#include "moc_qgsfutureutils.cpp"
19
21
22QgsCombinedFutureHelper::QgsCombinedFutureHelper( QList<QFuture<void>> futures, QFuture<void> cancellationFuture, std::function<void()> allFinishedCallback )
23 : mAllFinishedCallback( std::move( allFinishedCallback ) )
24{
25 mWatchers.resize( futures.size() );
26 for ( qsizetype i = 0; i < futures.size(); i++ )
27 {
28 mWatchers[i] = new QFutureWatcher<void>( this );
29 connect( mWatchers[i], &QFutureWatcherBase::finished, this, &QgsCombinedFutureHelper::onOneFinished );
30 mWatchers[i]->setFuture( futures[i] );
31 }
32 connect( &mCancellationWatcher, &QFutureWatcherBase::canceled, this, &QgsCombinedFutureHelper::onCanceled );
33 mCancellationWatcher.setFuture( cancellationFuture );
34}
35
36void QgsCombinedFutureHelper::onOneFinished()
37{
38 if ( mFired )
39 return;
40 // Check all futures are finished
41 for ( auto &watcher : std::as_const( mWatchers ) )
42 {
43 if ( !watcher->isFinished() )
44 return;
45 }
46 mFired = true;
47 mAllFinishedCallback();
48 deleteLater();
49}
50
51void QgsCombinedFutureHelper::onCanceled()
52{
53 for ( auto &watcher : std::as_const( mWatchers ) )
54 {
55 QgsFutureUtils::cancelChain( watcher->future() );
56 }
57}
58
60
61void QgsFutureUtils::waitForFinished( QFuture<void> future )
62{
63 if ( QThread::currentThread() == QCoreApplication::instance()->thread() )
64 {
65 // We can't block on the main thread (the future finishing may depend on
66 // some signal being delivered), so instead we manually spin the event loop
67 // until the future is finished.
68 // Running main loop events here is not without its dangers. If those
69 // events mutate something our calling code is working on (like with
70 // deleteLater()), we could get a nasty crash. Sadly QEventLoop doesn't
71 // allow us to filter on event types.
72 QEventLoop loop;
73 QFutureWatcher<void> watcher;
74 QObject::connect( &watcher, &QFutureWatcherBase::finished, &loop, &QEventLoop::quit );
75#ifdef QGISDEBUG
76 // Helps expose the issues talked about above
77 QCoreApplication::processEvents();
78#endif
79 watcher.setFuture( future );
80 if ( !watcher.isFinished() )
81 loop.exec();
82 // Make sure exceptions are thrown. Won't block because we waited above.
83 future.waitForFinished();
84 }
85 else
86 {
87 // On worker threads we can safely block
88 future.waitForFinished();
89 }
90}
91
92QFuture<void> QgsFutureUtils::clone( QFuture<void> base )
93{
94 auto watcher = new QFutureWatcher<void>;
95
96 QFuture<void> cloned = QtFuture::connect( watcher, &QFutureWatcherBase::finished ) //
97 .then( [watcher]() { watcher->deleteLater(); } );
98 watcher->setFuture( base );
99
100 return cloned;
101}
102
103void QgsFutureUtils::cancelChain( QFuture<void> future )
104{
105#if QT_VERSION >= QT_VERSION_CHECK( 6, 10, 0 )
106 future.cancelChain();
107#else
108 future.cancel();
109#endif
110}
static QFuture< void > clone(QFuture< void > base)
Returns a future that will finish at the same time base will.
static void cancelChain(QFuture< void > future)
Runs future.cancelChain() if supported by Qt version, future.cancel() otherwise.
static void waitForFinished(QFuture< void > future)
Waits for the future to become finished without blocking the main thread's event loop.