21 #include <QtConcurrentRun> 30 , mDescription( name )
36 Q_ASSERT_X( mStatus !=
Running,
"delete", QStringLiteral(
"status was %1" ).arg( mStatus ).toLatin1() );
37 mNotFinishedMutex.tryLock();
38 Q_FOREACH (
const SubTask &subTask, mSubTasks )
42 mNotFinishedMutex.unlock();
47 return mElapsedTime.elapsed();
52 mNotFinishedMutex.lock();
54 Q_ASSERT( mStartCount == 1 );
84 mShouldTerminate =
true;
93 processSubTasksForTermination();
96 Q_FOREACH (
const SubTask &subTask, mSubTasks )
98 subTask.task->cancel();
107 processSubTasksForHold();
110 Q_FOREACH (
const SubTask &subTask, mSubTasks )
112 subTask.task->hold();
125 Q_FOREACH (
const SubTask &subTask, mSubTasks )
127 subTask.task->unhold();
134 mSubTasks << SubTask( subTask, dependencies, subTaskDependency );
141 return _qgis_listQPointerToRaw( mDependentLayers );
154 timeout = std::numeric_limits< int >::max();
155 if ( mNotFinishedMutex.tryLock( timeout ) )
157 mNotFinishedMutex.unlock();
170 mDependentLayers = _qgis_listRawToQPointer( dependentLayers );
173 void QgsTask::subTaskStatusChanged(
int status )
186 processSubTasksForCompletion();
191 processSubTasksForTermination();
195 processSubTasksForHold();
208 if ( !mSubTasks.isEmpty() )
212 double totalProgress = 0.0;
213 Q_FOREACH (
const SubTask &subTask, mSubTasks )
217 totalProgress += 100.0;
221 totalProgress += subTask.task->progress();
224 progress = ( progress + totalProgress ) / ( mSubTasks.count() + 1 );
228 double prevProgress = mTotalProgress;
232 if ( static_cast< int >( prevProgress * 10 ) !=
static_cast< int >( mTotalProgress * 10 ) )
236 void QgsTask::completed()
239 processSubTasksForCompletion();
242 void QgsTask::processSubTasksForCompletion()
244 bool subTasksCompleted =
true;
245 Q_FOREACH (
const SubTask &subTask, mSubTasks )
247 if ( subTask.task->status() !=
Complete )
249 subTasksCompleted =
false;
254 if ( mStatus ==
Complete && subTasksCompleted )
261 mNotFinishedMutex.tryLock();
262 mNotFinishedMutex.unlock();
271 void QgsTask::processSubTasksForTermination()
273 bool subTasksTerminated =
true;
274 Q_FOREACH (
const SubTask &subTask, mSubTasks )
278 subTasksTerminated =
false;
289 mNotFinishedMutex.tryLock();
290 mNotFinishedMutex.unlock();
292 else if ( mStatus ==
Terminated && !subTasksTerminated )
299 void QgsTask::processSubTasksForHold()
301 bool subTasksRunning =
false;
302 Q_FOREACH (
const SubTask &subTask, mSubTasks )
304 if ( subTask.task->status() ==
Running )
306 subTasksRunning =
true;
311 if ( mStatus ==
OnHold && !subTasksRunning && mOverallStatus !=
OnHold )
316 else if ( mStatus ==
OnHold && subTasksRunning )
323 void QgsTask::terminated()
326 processSubTasksForTermination();
339 setAutoDelete(
true );
364 , mTaskMutex( new QMutex( QMutex::Recursive ) )
367 this, &QgsTaskManager::layersWillBeRemoved );
377 QMap< long, TaskInfo >
tasks = mTasks;
379 mTaskMutex->unlock();
380 QMap< long, TaskInfo >::const_iterator it = tasks.constBegin();
381 for ( ; it != tasks.constEnd(); ++it )
383 cleanupAndDeleteTask( it.value().task );
391 return addTaskPrivate( task,
QgsTaskList(),
false, priority );
396 return addTaskPrivate( definition.
task,
408 long taskId = mNextTaskId++;
411 mTasks.insert( taskId, TaskInfo( task, priority ) );
418 mParentTasks <<
task;
421 mLayerDependencies.insert( taskId, _qgis_listRawToQPointer( task->
dependentLayers() ) );
422 mTaskMutex->unlock();
431 Q_FOREACH (
const QgsTask::SubTask &subTask, task->mSubTasks )
433 switch ( subTask.dependency )
444 addTaskPrivate( subTask.task, subTask.dependencies,
true, priority );
452 if ( hasCircularDependencies( taskId ) )
468 QMutexLocker ml( mTaskMutex );
470 if ( mTasks.contains(
id ) )
471 t = mTasks.value(
id ).task;
477 QMutexLocker ml( mTaskMutex );
478 return mParentTasks.toList();
483 QMutexLocker ml( mTaskMutex );
484 return mParentTasks.count();
492 QMutexLocker ml( mTaskMutex );
493 QMap< long, TaskInfo >::const_iterator it = mTasks.constBegin();
494 for ( ; it != mTasks.constEnd(); ++it )
496 if ( it.value().task ==
task )
507 QSet< QgsTask * > parents = mParentTasks;
509 mTaskMutex->unlock();
511 Q_FOREACH (
QgsTask *task, parents )
520 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
521 dependencies.detach();
522 mTaskMutex->unlock();
524 if ( !dependencies.contains( taskId ) )
527 Q_FOREACH (
QgsTask *task, dependencies.value( taskId ) )
539 if ( resolveDependencies( taskId, taskId, results ) )
545 bool QgsTaskManager::resolveDependencies(
long firstTaskId,
long currentTaskId, QSet<long> &results )
const 548 QMap< long, QgsTaskList >
dependencies = mTaskDependencies;
549 dependencies.detach();
550 mTaskMutex->unlock();
552 if ( !dependencies.contains( currentTaskId ) )
555 Q_FOREACH (
QgsTask *task, dependencies.value( currentTaskId ) )
557 long dependentTaskId =
taskId( task );
558 if ( dependentTaskId >= 0 )
560 if ( dependentTaskId == firstTaskId )
565 results.insert( dependentTaskId );
567 QSet< long > newTaskDeps;
568 if ( !resolveDependencies( firstTaskId, dependentTaskId, newTaskDeps ) )
571 if ( newTaskDeps.contains( firstTaskId ) )
577 results.unite( newTaskDeps );
584 bool QgsTaskManager::hasCircularDependencies(
long taskId )
const 587 return !resolveDependencies( taskId, taskId, d );
592 QMutexLocker ml( mTaskMutex );
598 QMutexLocker ml( mTaskMutex );
599 QList< QgsTask * >
tasks;
600 QMap< long, QgsWeakMapLayerPointerList >::const_iterator layerIt = mLayerDependencies.constBegin();
601 for ( ; layerIt != mLayerDependencies.constEnd(); ++layerIt )
603 if ( _qgis_listQPointerToRaw( layerIt.value() ).contains( layer ) )
615 QMutexLocker ml( mTaskMutex );
617 activeTasks.intersect( mParentTasks );
618 return activeTasks.toList();
623 QMutexLocker ml( mTaskMutex );
624 QSet< QgsTask * >
tasks = mActiveTasks;
625 return tasks.intersect( mParentTasks ).count();
634 void QgsTaskManager::taskProgressChanged(
double progress )
651 void QgsTaskManager::taskStatusChanged(
int status )
661 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
662 mTaskMutex->unlock();
664 QThreadPool::globalInstance()->cancel( runnable );
675 cancelDependentTasks(
id );
679 bool isParent = mParentTasks.contains( task );
680 mTaskMutex->unlock();
691 cleanupAndDeleteTask( task );
696 void QgsTaskManager::layersWillBeRemoved(
const QList< QgsMapLayer * > &layers )
700 QMap< long, QgsWeakMapLayerPointerList > layerDependencies = mLayerDependencies;
701 layerDependencies.detach();
702 mTaskMutex->unlock();
707 for ( QMap< long, QgsWeakMapLayerPointerList >::const_iterator it = layerDependencies.constBegin();
708 it != layerDependencies.constEnd(); ++it )
710 if ( !( _qgis_listQPointerToRaw( it.value() ).contains( layer ) ) )
727 bool QgsTaskManager::cleanupAndDeleteTask(
QgsTask *task )
736 QgsTaskRunnableWrapper *runnable = mTasks.value(
id ).runnable;
738 task->disconnect(
this );
741 if ( mTaskDependencies.contains(
id ) )
742 mTaskDependencies.remove(
id );
743 mTaskMutex->unlock();
748 bool isParent = mParentTasks.contains( task );
749 mParentTasks.remove( task );
750 mSubTasks.remove( task );
752 mLayerDependencies.remove(
id );
767 QThreadPool::globalInstance()->cancel( runnable );
776 for ( QMap< long, QgsTaskList >::iterator it = mTaskDependencies.begin(); it != mTaskDependencies.end(); ++it )
778 if ( it.value().contains( task ) )
780 it.value().removeAll( task );
783 mTaskMutex->unlock();
788 void QgsTaskManager::processQueue()
792 mActiveTasks.clear();
793 for ( QMap< long, TaskInfo >::iterator it = mTasks.begin(); it != mTasks.end(); ++it )
795 QgsTask *task = it.value().task;
798 it.value().createRunnable();
799 QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
804 mActiveTasks <<
task;
808 bool allFinished = mActiveTasks.isEmpty();
809 mTaskMutex->unlock();
817 if ( prevActiveCount != newActiveCount )
823 void QgsTaskManager::cancelDependentTasks(
long taskId )
829 QMap< long, QgsTaskList > taskDependencies = mTaskDependencies;
830 taskDependencies.detach();
831 mTaskMutex->unlock();
833 QMap< long, QgsTaskList >::const_iterator it = taskDependencies.constBegin();
834 for ( ; it != taskDependencies.constEnd(); ++it )
836 if ( it.value().contains( canceledTask ) )
849 QgsTaskManager::TaskInfo::TaskInfo(
QgsTask *task,
int priority )
852 , priority( priority )
855 void QgsTaskManager::TaskInfo::createRunnable()
857 Q_ASSERT( !runnable );
858 runnable =
new QgsTaskRunnableWrapper( task );
bool dependenciesSatisfied(long taskId) const
Returns true if all dependencies for the specified task are satisfied.
int countActiveTasks() const
Returns the number of active (queued or running) tasks.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e...
void setProgress(double progress)
Sets the task's current progress.
Base class for all map layer types.
void hold()
Places the task on hold.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTriggered(QgsTask *task)
Emitted when a task is triggered.
QList< QgsMapLayer *> dependentLayers() const
Returns the list of layers on which the task depends.
QgsTask(const QString &description=QString(), QgsTask::Flags flags=AllFlags)
Constructor for QgsTask.
void statusChanged(int status)
Will be emitted by task when its status changes.
QList< QgsTask *> QgsTaskList
List of QgsTask objects.
int count() const
Returns the number of tasks tracked by the manager.
Subtask must complete before parent can begin.
qint64 elapsedTime() const
Returns the elapsed time since the task commenced, in milliseconds.
QgsTaskManager(QObject *parent=nullptr)
Constructor for QgsTaskManager.
void setDependentLayers(const QList< QgsMapLayer *> &dependentLayers)
Sets a list of layers on which the task depends.
bool waitForFinished(int timeout=30000)
Blocks the current thread until the task finishes or a maximum of timeout milliseconds.
QList< QgsTask * > tasks() const
Returns all tasks tracked by the manager.
void begun()
Will be emitted by task to indicate its commencement.
SubTaskDependency
Controls how subtasks relate to their parent task.
void cancelAll()
Instructs all tasks tracked by the manager to terminate.
QgsTaskList dependentTasks
List of dependent tasks which must be completed before task can run.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
QSet< long > dependencies(long taskId) const
Returns the set of task IDs on which a task is dependent.
void taskAboutToBeDeleted(long taskId)
Emitted when a task is about to be deleted.
Task was terminated or errored.
void countActiveTasksChanged(int count)
Emitted when the number of active tasks changes.
void triggerTask(QgsTask *task)
Triggers a task, e.g.
QList< QgsTask *> tasksDependentOnLayer(QgsMapLayer *layer) const
Returns a list of tasks which depend on a layer.
QgsTask * task(long id) const
Returns the task with matching ID.
void progressChanged(long taskId, double progress)
Will be emitted when a task reports a progress change.
Definition of a task for inclusion in the manager.
Task is queued but on hold and will not be started.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Abstract base class for long running background tasks.
Reads and writes project states.
friend class QgsTaskRunnableWrapper
void statusChanged(long taskId, int status)
Will be emitted when a task reports a status change.
Task successfully completed.
void taskAdded(long taskId)
Emitted when a new task has been added to the manager.
virtual void cancel()
Notifies the task that it should terminate.
void allTasksFinished()
Emitted when all tasks are complete.
Task is queued and has not begun.
double progress() const
Returns the task's progress (between 0.0 and 100.0)
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QList< QgsTask *> activeTasks() const
Returns a list of the active (queued or running) tasks.
Task is currently running.
~QgsTaskManager() override
QList< QgsWeakMapLayerPointer > QgsWeakMapLayerPointerList
A list of weak pointers to QgsMapLayers.
static QgsProject * instance()
Returns the QgsProject singleton instance.
long taskId(QgsTask *task) const
Returns the unique task ID corresponding to a task managed by the class.
virtual void finished(bool result)
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
virtual bool run()=0
Performs the task's operation.
void finalTaskProgressChanged(double progress)
Will be emitted when only a single task remains to complete and that task has reported a progress cha...
Subtask is independent of the parent, and can run before, after or at the same time as the parent...
void addSubTask(QgsTask *subTask, const QgsTaskList &dependencies=QgsTaskList(), SubTaskDependency subTaskDependency=SubTaskIndependent)
Adds a subtask to this task.
void unhold()
Releases the task from being held.
TaskStatus status() const
Returns the current task status.
QList< QgsMapLayer *> dependentLayers(long taskId) const
Returns a list of layers on which as task is dependent.