Skip to content

Commit

Permalink
QgsTask is no longer a QRunnable
Browse files Browse the repository at this point in the history
Instead use a private wrapper class to make QgsTask compatible
with QThreadPool
  • Loading branch information
nyalldawson committed Dec 5, 2016
1 parent 29f310c commit 297b572
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 33 deletions.
2 changes: 1 addition & 1 deletion python/core/__init__.py
Expand Up @@ -208,7 +208,7 @@ def __init__(self, description, flags, function, on_finished, *args, **kwargs):
self.returned_values = None
self.exception = None

def _run(self):
def run(self):
try:
self.returned_values = self.function(self, *self.args, **self.kwargs)
except Exception as ex:
Expand Down
6 changes: 3 additions & 3 deletions python/core/qgstaskmanager.sip
Expand Up @@ -14,7 +14,7 @@
*
* \note Added in version 3.0
*/
class QgsTask : QObject, QRunnable
class QgsTask : QObject
{

%TypeHeaderCode
Expand Down Expand Up @@ -92,7 +92,7 @@ class QgsTask : QObject, QRunnable
* then this method should not be called directly, instead it is left to the
* task manager to start the task when appropriate.
*/
void run();
void start();

/**
* Notifies the task that it should terminate. Calling this is not guaranteed
Expand Down Expand Up @@ -211,7 +211,7 @@ class QgsTask : QObject, QRunnable
* @see completed()
* @see terminated()
*/
virtual TaskResult _run() = 0;
virtual TaskResult run() = 0;

/**
* If the task is managed by a QgsTaskManager, this will be called after the
Expand Down
58 changes: 48 additions & 10 deletions src/core/qgstaskmanager.cpp
Expand Up @@ -34,23 +34,19 @@ QgsTask::QgsTask( const QString &name, const Flags& flags )
, mTotalProgress( 0.0 )
, mShouldTerminate( false )
, mStartCount( 0 )
{
setAutoDelete( false );
}
{}

QgsTask::~QgsTask()
{
Q_ASSERT_X( mStatus != Running, "delete", QString( "status was %1" ).arg( mStatus ).toLatin1() );

QThreadPool::globalInstance()->cancel( this );

Q_FOREACH ( const SubTask& subTask, mSubTasks )
{
delete subTask.task;
}
}

void QgsTask::run()
void QgsTask::start()
{
mStartCount++;
Q_ASSERT( mStartCount == 1 );
Expand All @@ -66,7 +62,7 @@ void QgsTask::run()
// force initial emission of progressChanged, but respect if task has had initial progress manually set
setProgress( mProgress );

TaskResult result = _run();
TaskResult result = run();
switch ( result )
{
case ResultSuccess:
Expand Down Expand Up @@ -94,7 +90,6 @@ void QgsTask::cancel()

#if QT_VERSION >= 0x050500
//can't cancel queued tasks with qt < 5.5
QThreadPool::globalInstance()->cancel( this );
if ( mStatus == Queued || mStatus == OnHold )
{
// immediately terminate unstarted jobs
Expand Down Expand Up @@ -296,6 +291,35 @@ void QgsTask::terminated()
}


///@cond PRIVATE

class QgsTaskRunnableWrapper : public QRunnable
{
public:

QgsTaskRunnableWrapper( QgsTask* task )
: QRunnable()
, mTask( task )
{
setAutoDelete( true );
}

void run() override
{
Q_ASSERT( mTask );
mTask->start();
}

private:

QgsTask* mTask;

};

///@endcond



//
// QgsTaskManager
//
Expand Down Expand Up @@ -594,6 +618,11 @@ void QgsTaskManager::taskStatusChanged( int status )
if ( id < 0 )
return;

#if QT_VERSION >= 0x050500
QgsTaskRunnableWrapper* runnable = mTasks.value( id ).runnable;
QThreadPool::globalInstance()->cancel( runnable );
#endif

if ( status == QgsTask::Terminated || status == QgsTask::Complete )
{
QgsTask::TaskResult result = status == QgsTask::Complete ? QgsTask::ResultSuccess
Expand Down Expand Up @@ -665,6 +694,8 @@ bool QgsTaskManager::cleanupAndDeleteTask( QgsTask *task )
if ( id < 0 )
return false;

QgsTaskRunnableWrapper* runnable = mTasks.value( id ).runnable;

task->disconnect( this );

mDependenciesMutex->lockForWrite();
Expand Down Expand Up @@ -707,7 +738,7 @@ bool QgsTaskManager::cleanupAndDeleteTask( QgsTask *task )
else
{
#if QT_VERSION >= 0x050500
QThreadPool::globalInstance()->cancel( task );
QThreadPool::globalInstance()->cancel( runnable );
#endif
if ( isParent )
{
Expand Down Expand Up @@ -741,7 +772,7 @@ void QgsTaskManager::processQueue()
QgsTask* task = it.value().task;
if ( task && task->mStatus == QgsTask::Queued && dependenciesSatisified( it.key() ) && it.value().added.testAndSetRelaxed( 0, 1 ) )
{
QThreadPool::globalInstance()->start( task, it.value().priority );
QThreadPool::globalInstance()->start( it.value().runnable, it.value().priority );
}

if ( task && ( task->mStatus != QgsTask::Complete && task->mStatus != QgsTask::Terminated ) )
Expand Down Expand Up @@ -792,3 +823,10 @@ void QgsTaskManager::cancelDependentTasks( long taskId )
}
}
}

QgsTaskManager::TaskInfo::TaskInfo( QgsTask* task, int priority )
: task( task )
, added( 0 )
, priority( priority )
, runnable( new QgsTaskRunnableWrapper( task ) )
{}
17 changes: 7 additions & 10 deletions src/core/qgstaskmanager.h
Expand Up @@ -24,6 +24,7 @@
#include <QReadWriteLock>

class QgsTask;
class QgsTaskRunnableWrapper;

//! List of QgsTask objects
typedef QList< QgsTask* > QgsTaskList;
Expand All @@ -35,7 +36,7 @@ typedef QList< QgsTask* > QgsTaskList;
* or added to a QgsTaskManager for automatic management.
*
* Derived classes should implement the process they want to execute in the background
* within the _run() method. This method will be called when the
* within the run() method. This method will be called when the
* task commences (ie via calling run() ).
*
* Long running tasks should periodically check the isCancelled() flag to detect if the task
Expand All @@ -44,7 +45,7 @@ typedef QList< QgsTask* > QgsTaskList;
*
* \note Added in version 3.0
*/
class CORE_EXPORT QgsTask : public QObject, public QRunnable
class CORE_EXPORT QgsTask : public QObject
{
Q_OBJECT

Expand Down Expand Up @@ -122,7 +123,7 @@ class CORE_EXPORT QgsTask : public QObject, public QRunnable
* then this method should not be called directly, instead it is left to the
* task manager to start the task when appropriate.
*/
void run() override;
void start();

/**
* Notifies the task that it should terminate. Calling this is not guaranteed
Expand Down Expand Up @@ -242,7 +243,7 @@ class CORE_EXPORT QgsTask : public QObject, public QRunnable
* @see completed()
* @see terminated()
*/
virtual TaskResult _run() = 0;
virtual TaskResult run() = 0;

/**
* If the task is managed by a QgsTaskManager, this will be called after the
Expand Down Expand Up @@ -334,7 +335,6 @@ class CORE_EXPORT QgsTask : public QObject, public QRunnable

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsTask::Flags )


/** \ingroup core
* \class QgsTaskManager
* \brief Task manager for managing a set of long-running QgsTask tasks. This class can be created directly,
Expand Down Expand Up @@ -496,14 +496,11 @@ class CORE_EXPORT QgsTaskManager : public QObject

struct TaskInfo
{
TaskInfo( QgsTask* task = nullptr, int priority = 0 )
: task( task )
, added( 0 )
, priority( priority )
{}
TaskInfo( QgsTask* task = nullptr, int priority = 0 );
QgsTask* task;
QAtomicInt added;
int priority;
QgsTaskRunnableWrapper* runnable;
};

mutable QReadWriteLock* mTaskMutex;
Expand Down
18 changes: 9 additions & 9 deletions tests/src/core/testqgstaskmanager.cpp
Expand Up @@ -40,7 +40,7 @@ class TestTask : public QgsTask

protected:

TaskResult _run() override
TaskResult run() override
{
runCalled = true;
return ResultPending;
Expand All @@ -62,7 +62,7 @@ class TestTerminationTask : public TestTask

protected:

TaskResult _run() override
TaskResult run() override
{
while ( !isCancelled() )
{}
Expand All @@ -85,7 +85,7 @@ class CancelableTask : public QgsTask

protected:

TaskResult _run() override
TaskResult run() override
{
while ( !isCancelled() )
{}
Expand All @@ -99,7 +99,7 @@ class SuccessTask : public QgsTask

protected:

TaskResult _run() override
TaskResult run() override
{
return ResultSuccess;
}
Expand All @@ -111,7 +111,7 @@ class FailTask : public QgsTask

protected:

TaskResult _run() override
TaskResult run() override
{
return ResultFail;
}
Expand All @@ -134,7 +134,7 @@ class FinishTask : public QgsTask

protected:

TaskResult _run() override
TaskResult run() override
{
return desiredResult;
}
Expand Down Expand Up @@ -218,7 +218,7 @@ void TestQgsTaskManager::task()
QSignalSpy startedSpy( task.data(), &QgsTask::begun );
QSignalSpy statusSpy( task.data(), &QgsTask::statusChanged );

task->run();
task->start();
QCOMPARE( task->status(), QgsTask::Running );
QVERIFY( task->isActive() );
QVERIFY( task->runCalled );
Expand Down Expand Up @@ -270,7 +270,7 @@ void TestQgsTaskManager::taskResult()
QCOMPARE( task->status(), QgsTask::Queued );
QSignalSpy statusSpy( task.data(), &QgsTask::statusChanged );

task->run();
task->start();
QCOMPARE( statusSpy.count(), 2 );
QCOMPARE( static_cast< QgsTask::TaskStatus >( statusSpy.at( 0 ).at( 0 ).toInt() ), QgsTask::Running );
QCOMPARE( static_cast< QgsTask::TaskStatus >( statusSpy.at( 1 ).at( 0 ).toInt() ), QgsTask::Complete );
Expand All @@ -280,7 +280,7 @@ void TestQgsTaskManager::taskResult()
QCOMPARE( task->status(), QgsTask::Queued );
QSignalSpy statusSpy2( task.data(), &QgsTask::statusChanged );

task->run();
task->start();
QCOMPARE( statusSpy2.count(), 2 );
QCOMPARE( static_cast< QgsTask::TaskStatus >( statusSpy2.at( 0 ).at( 0 ).toInt() ), QgsTask::Running );
QCOMPARE( static_cast< QgsTask::TaskStatus >( statusSpy2.at( 1 ).at( 0 ).toInt() ), QgsTask::Terminated );
Expand Down

0 comments on commit 297b572

Please sign in to comment.