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 );