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 , mTaskMutex( new QMutex( QMutex::Recursive ) )
404 QMap< long, TaskInfo >
tasks = mTasks;
406 mTaskMutex->unlock();
407 QMap< long, TaskInfo >::const_iterator it =
tasks.constBegin();
408 for ( ; it !=
tasks.constEnd(); ++it )
410 cleanupAndDeleteTask( it.value().task );
423 return addTaskPrivate( definition.
task,
430 long QgsTaskManager::addTaskPrivate(
QgsTask *task,
QgsTaskList dependencies,
bool isSubTask,
int priority )
441 this, &QgsTaskManager::layersWillBeRemoved );
444 long taskId = mNextTaskId++;
447 mTasks.insert(
taskId, TaskInfo(
task, priority ) );
454 mParentTasks <<
task;
458 mTaskMutex->unlock();
467 for (
const QgsTask::SubTask &subTask : qgis::as_const(
task->mSubTasks ) )
469 switch ( subTask.dependency )
480 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
488 if ( hasCircularDependencies(
taskId ) )
504 QMutexLocker ml( mTaskMutex );
506 if ( mTasks.contains(
id ) )
507 t = mTasks.value(
id ).task;
513 QMutexLocker ml( mTaskMutex );
514 return qgis::setToList( mParentTasks );
519 QMutexLocker ml( mTaskMutex );
520 return mParentTasks.count();
528 QMutexLocker ml( mTaskMutex );
529 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
530 for ( ; it != mTasks.constEnd(); ++it )
532 if ( it.value().task ==
task )
543 QSet< QgsTask * > parents = mParentTasks;
545 mTaskMutex->unlock();
547 const auto constParents = parents;
557 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
559 mTaskMutex->unlock();
583 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const
586 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
588 mTaskMutex->unlock();
593 const auto constValue =
dependencies.value( currentTaskId );
597 if ( dependentTaskId >= 0 )
599 if ( dependentTaskId == firstTaskId )
604 results.insert( dependentTaskId );
606 QSet< long > newTaskDeps;
607 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
610 if ( newTaskDeps.contains( firstTaskId ) )
616 results.unite( newTaskDeps );
623 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const
631 QMutexLocker ml( mTaskMutex );
637 QMutexLocker ml( mTaskMutex );
638 QList< QgsTask * >
tasks;
639 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
640 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
642 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
654 QMutexLocker ml( mTaskMutex );
662 QMutexLocker ml( mTaskMutex );
663 QSet< QgsTask * >
tasks = mActiveTasks;
664 return tasks.intersect( mParentTasks ).count();
673 void QgsTaskManager::taskProgressChanged(
double progress )
675 QgsTask *
task = qobject_cast< QgsTask * >( sender() );
690 void QgsTaskManager::taskStatusChanged(
int status )
692 QgsTask *
task = qobject_cast< QgsTask * >( sender() );
700 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
701 mTaskMutex->unlock();
702 if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
705 mTasks[ id ].runnable =
nullptr;
717 cancelDependentTasks(
id );
721 bool isParent = mParentTasks.contains(
task );
722 mTaskMutex->unlock();
733 cleanupAndDeleteTask(
task );
738 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
742 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
743 layerDependencies.detach();
744 mTaskMutex->unlock();
746 const auto constLayers = layers;
750 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
751 it != layerDependencies.constEnd(); ++it )
753 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
770 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
779 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
781 task->disconnect(
this );
784 if ( mTaskDependencies.contains(
id ) )
785 mTaskDependencies.remove(
id );
786 mTaskMutex->unlock();
791 bool isParent = mParentTasks.contains(
task );
792 mParentTasks.remove(
task );
793 mSubTasks.remove(
task );
795 mLayerDependencies.remove(
id );
809 if ( runnable && QThreadPool::globalInstance()->tryTake( runnable ) )
812 mTasks[ id ].runnable =
nullptr;
823 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
825 if ( it.value().contains(
task ) )
827 it.value().removeAll(
task );
830 mTaskMutex->unlock();
835 void QgsTaskManager::processQueue()
839 mActiveTasks.clear();
840 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
845 it.value().createRunnable();
846 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
851 mActiveTasks <<
task;
855 bool allFinished = mActiveTasks.isEmpty();
856 mTaskMutex->unlock();
864 if ( prevActiveCount != newActiveCount )
870 void QgsTaskManager::cancelDependentTasks(
long taskId )
876 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
877 taskDependencies.detach();
878 mTaskMutex->unlock();
880 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
881 for ( ; it != taskDependencies.constEnd(); ++it )
883 if ( it.value().contains( canceledTask ) )
896 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
899 , priority( priority )
902 void QgsTaskManager::TaskInfo::createRunnable()
904 Q_ASSERT( !runnable );
905 runnable =
new QgsTaskRunnableWrapper( task );