22 #include <QtConcurrentRun>
31 , mDescription( name )
32 , mNotStartedMutex( 1 )
34 mNotStartedMutex.acquire();
39 Q_ASSERT_X( mStatus !=
Running,
"delete", QStringLiteral(
"status was %1" ).arg( mStatus ).toLatin1() );
41 mNotFinishedMutex.lock();
42 const auto constMSubTasks = mSubTasks;
43 for (
const SubTask &subTask : constMSubTasks )
47 mNotFinishedMutex.unlock();
48 mNotStartedMutex.release();
58 return mElapsedTime.elapsed();
63 QMutexLocker locker( &mNotFinishedMutex );
64 mNotStartedMutex.release();
66 Q_ASSERT( mStartCount == 1 );
96 mShouldTerminateMutex.lock();
97 mShouldTerminate =
true;
98 mShouldTerminateMutex.unlock();
103 mNotStartedMutex.release();
108 processSubTasksForTermination();
111 const auto constMSubTasks = mSubTasks;
112 for (
const SubTask &subTask : constMSubTasks )
114 subTask.task->cancel();
120 QMutexLocker locker( &mShouldTerminateMutex );
121 return mShouldTerminate;
129 processSubTasksForHold();
132 const auto constMSubTasks = mSubTasks;
133 for (
const SubTask &subTask : constMSubTasks )
135 subTask.task->hold();
148 const auto constMSubTasks = mSubTasks;
149 for (
const SubTask &subTask : constMSubTasks )
151 subTask.task->unhold();
158 mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
165 return _qgis_listQPointerToRaw( mDependentLayers );
171 mNotStartedMutex.acquire();
181 timeout = std::numeric_limits< int >::max();
182 if ( mNotFinishedMutex.tryLock( timeout ) )
184 mNotFinishedMutex.unlock();
185 QCoreApplication::sendPostedEvents(
this );
201 void QgsTask::subTaskStatusChanged(
int status )
203 QgsTask *subTask = qobject_cast< QgsTask * >( sender() );
214 processSubTasksForCompletion();
219 processSubTasksForTermination();
223 processSubTasksForHold();
236 if ( !mSubTasks.isEmpty() )
240 double totalProgress = 0.0;
241 const auto constMSubTasks = mSubTasks;
242 for (
const SubTask &subTask : constMSubTasks )
246 totalProgress += 100.0;
250 totalProgress += subTask.task->
progress();
257 double prevProgress = mTotalProgress;
261 if (
static_cast< int >( prevProgress * 10 ) !=
static_cast< int >( mTotalProgress * 10 ) )
265 void QgsTask::completed()
268 QMetaObject::invokeMethod(
this,
"processSubTasksForCompletion" );
271 void QgsTask::processSubTasksForCompletion()
273 bool subTasksCompleted =
true;
274 const auto constMSubTasks = mSubTasks;
275 for (
const SubTask &subTask : constMSubTasks )
279 subTasksCompleted =
false;
284 if ( mStatus ==
Complete && subTasksCompleted )
299 void QgsTask::processSubTasksForTermination()
301 bool subTasksTerminated =
true;
302 const auto constMSubTasks = mSubTasks;
303 for (
const SubTask &subTask : constMSubTasks )
307 subTasksTerminated =
false;
319 else if ( mStatus ==
Terminated && !subTasksTerminated )
326 void QgsTask::processSubTasksForHold()
328 bool subTasksRunning =
false;
329 const auto constMSubTasks = mSubTasks;
330 for (
const SubTask &subTask : constMSubTasks )
334 subTasksRunning =
true;
339 if ( mStatus ==
OnHold && !subTasksRunning && mOverallStatus !=
OnHold )
344 else if ( mStatus ==
OnHold && subTasksRunning )
351 void QgsTask::terminated()
354 QMetaObject::invokeMethod(
this,
"processSubTasksForTermination" );
360 class QgsTaskRunnableWrapper :
public QRunnable
364 explicit QgsTaskRunnableWrapper(
QgsTask *task )
367 setAutoDelete(
true );
392 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
393 , mTaskMutex( new QMutex( QMutex::Recursive ) )
395 , mTaskMutex( new QRecursiveMutex() )
408 QMap< long, TaskInfo >
tasks = mTasks;
410 mTaskMutex->unlock();
411 QMap< long, TaskInfo >::const_iterator it =
tasks.constBegin();
412 for ( ; it !=
tasks.constEnd(); ++it )
414 cleanupAndDeleteTask( it.value().task );
427 return addTaskPrivate( definition.
task,
434 long QgsTaskManager::addTaskPrivate(
QgsTask *task,
QgsTaskList dependencies,
bool isSubTask,
int priority )
445 this, &QgsTaskManager::layersWillBeRemoved );
448 long taskId = mNextTaskId++;
451 mTasks.insert(
taskId, TaskInfo(
task, priority ) );
458 mParentTasks <<
task;
462 mTaskMutex->unlock();
471 for (
const QgsTask::SubTask &subTask : std::as_const(
task->mSubTasks ) )
473 switch ( subTask.dependency )
484 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
492 if ( hasCircularDependencies(
taskId ) )
510 QMutexLocker ml( mTaskMutex );
512 if ( mTasks.contains(
id ) )
513 t = mTasks.value(
id ).task;
519 QMutexLocker ml( mTaskMutex );
520 return qgis::setToList( mParentTasks );
525 QMutexLocker ml( mTaskMutex );
526 return mParentTasks.count();
534 QMutexLocker ml( mTaskMutex );
535 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
536 for ( ; it != mTasks.constEnd(); ++it )
538 if ( it.value().task ==
task )
549 QSet< QgsTask * > parents = mParentTasks;
551 mTaskMutex->unlock();
553 const auto constParents = parents;
563 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
565 mTaskMutex->unlock();
589 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const
592 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
594 mTaskMutex->unlock();
599 const auto constValue =
dependencies.value( currentTaskId );
603 if ( dependentTaskId >= 0 )
605 if ( dependentTaskId == firstTaskId )
610 results.insert( dependentTaskId );
612 QSet< long > newTaskDeps;
613 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
616 if ( newTaskDeps.contains( firstTaskId ) )
622 results.unite( newTaskDeps );
629 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const
637 QMutexLocker ml( mTaskMutex );
643 QMutexLocker ml( mTaskMutex );
644 QList< QgsTask * >
tasks;
645 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
646 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
648 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
660 QMutexLocker ml( mTaskMutex );
668 QMutexLocker ml( mTaskMutex );
669 QSet< QgsTask * >
tasks = mActiveTasks;
671 if ( !includeHidden )
673 QSet< QgsTask * > filteredTasks;
674 filteredTasks.reserve(
tasks.size() );
678 filteredTasks.insert(
task );
680 tasks = filteredTasks;
683 return tasks.intersect( mParentTasks ).count();
692 void QgsTaskManager::taskProgressChanged(
double progress )
694 QgsTask *
task = qobject_cast< QgsTask * >( sender() );
711 void QgsTaskManager::taskStatusChanged(
int status )
713 QgsTask *
task = qobject_cast< QgsTask * >( sender() );
722 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
723 mTaskMutex->unlock();
724 if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
727 mTasks[ id ].runnable =
nullptr;
739 cancelDependentTasks(
id );
743 bool isParent = mParentTasks.contains(
task );
744 mTaskMutex->unlock();
745 if ( isParent && !isHidden )
755 cleanupAndDeleteTask(
task );
760 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
764 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
765 layerDependencies.detach();
766 mTaskMutex->unlock();
768 const auto constLayers = layers;
772 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
773 it != layerDependencies.constEnd(); ++it )
775 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
792 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
801 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
803 task->disconnect(
this );
806 if ( mTaskDependencies.contains(
id ) )
807 mTaskDependencies.remove(
id );
808 mTaskMutex->unlock();
813 bool isParent = mParentTasks.contains(
task );
814 mParentTasks.remove(
task );
815 mSubTasks.remove(
task );
817 mLayerDependencies.remove(
id );
831 if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
834 mTasks[ id ].runnable =
nullptr;
845 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
847 if ( it.value().contains(
task ) )
849 it.value().removeAll(
task );
852 mTaskMutex->unlock();
857 void QgsTaskManager::processQueue()
861 mActiveTasks.clear();
862 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
867 it.value().createRunnable();
868 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
873 mActiveTasks <<
task;
877 bool allFinished = mActiveTasks.isEmpty();
878 mTaskMutex->unlock();
886 if ( prevActiveCount != newActiveCount )
892 void QgsTaskManager::cancelDependentTasks(
long taskId )
898 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
899 taskDependencies.detach();
900 mTaskMutex->unlock();
902 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
903 for ( ; it != taskDependencies.constEnd(); ++it )
905 if ( it.value().contains( canceledTask ) )
918 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
921 , priority( priority )
924 void QgsTaskManager::TaskInfo::createRunnable()
926 Q_ASSERT( !runnable );
927 runnable =
new QgsTaskRunnableWrapper( task );