Skip to content

Commit

Permalink
Merge pull request #5230 from m-kuhn/taskWaitForFinished
Browse files Browse the repository at this point in the history
QgsTask::waitForFinished without event loop
  • Loading branch information
m-kuhn committed Sep 21, 2017
2 parents 8ef28e3 + 8f2c885 commit 9caa722
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 23 deletions.
4 changes: 2 additions & 2 deletions python/core/qgstaskmanager.sip
Expand Up @@ -170,10 +170,10 @@ class QgsTask : QObject
:rtype: list of QgsMapLayer
%End

bool waitForFinished( int timeout = 30000 );
bool waitForFinished( unsigned long timeout = 30000 );
%Docstring
Blocks the current thread until the task finishes or a maximum of ``timeout`` milliseconds.
If the ``timeout`` is ``-1`` the thread will be blocked forever.
If ``timeout`` is ``0`` the thread will be blocked forever.
In case of a timeout, the task will still be running.
In case the task already is finished, the method will return immediately while
returning ``true``.
Expand Down
37 changes: 20 additions & 17 deletions src/core/qgstaskmanager.cpp
Expand Up @@ -35,7 +35,9 @@ QgsTask::QgsTask( const QString &name, const Flags &flags )
, mTotalProgress( 0.0 )
, mShouldTerminate( false )
, mStartCount( 0 )
{}
{
mNotFinishedMutex.lock();
}

QgsTask::~QgsTask()
{
Expand Down Expand Up @@ -142,26 +144,19 @@ QList<QgsMapLayer *> QgsTask::dependentLayers() const
return _qgis_listQPointerToRaw( mDependentLayers );
}

bool QgsTask::waitForFinished( int timeout )
bool QgsTask::waitForFinished( unsigned long timeout )
{
QEventLoop loop;
bool rv = true;

connect( this, &QgsTask::taskCompleted, &loop, &QEventLoop::quit );
connect( this, &QgsTask::taskTerminated, &loop, &QEventLoop::quit );
QTimer timer;

if ( timeout != -1 )
if ( mOverallStatus == Complete || mOverallStatus == Terminated )
{
timer.start( timeout );
connect( &timer, &QTimer::timeout, [&rv]() { rv = false; } );
connect( &timer, &QTimer::timeout, &loop, &QEventLoop::quit );
rv = true;
}
else
{
if ( timeout == 0 )
timeout = ULONG_MAX;
rv = mTaskFinished.wait( &mNotFinishedMutex, timeout );
}

if ( status() == QgsTask::Complete || status() == QgsTask::Terminated )
return true;
loop.exec();

return rv;
}

Expand Down Expand Up @@ -249,9 +244,13 @@ void QgsTask::processSubTasksForCompletion()
if ( mStatus == Complete && subTasksCompleted )
{
mOverallStatus = Complete;

setProgress( 100.0 );
emit statusChanged( Complete );
emit taskCompleted();
mTaskFinished.wakeAll();
mNotFinishedMutex.unlock();
mTaskFinished.wakeAll();
}
else if ( mStatus == Complete )
{
Expand All @@ -275,8 +274,12 @@ void QgsTask::processSubTasksForTermination()
if ( mStatus == Terminated && subTasksTerminated && mOverallStatus != Terminated )
{
mOverallStatus = Terminated;

emit statusChanged( Terminated );
emit taskTerminated();
mTaskFinished.wakeAll();
mNotFinishedMutex.unlock();
mTaskFinished.wakeAll();
}
else if ( mStatus == Terminated && !subTasksTerminated )
{
Expand Down
10 changes: 8 additions & 2 deletions src/core/qgstaskmanager.h
Expand Up @@ -188,14 +188,14 @@ class CORE_EXPORT QgsTask : public QObject

/**
* Blocks the current thread until the task finishes or a maximum of \a timeout milliseconds.
* If the \a timeout is ``-1`` the thread will be blocked forever.
* If \a timeout is ``0`` the thread will be blocked forever.
* In case of a timeout, the task will still be running.
* In case the task already is finished, the method will return immediately while
* returning ``true``.
*
* The result will be false if the wait timed out and true in any other case.
*/
bool waitForFinished( int timeout = 30000 );
bool waitForFinished( unsigned long timeout = 30000 );

signals:

Expand Down Expand Up @@ -290,13 +290,19 @@ class CORE_EXPORT QgsTask : public QObject
//! Status of this task and all subtasks
TaskStatus mOverallStatus;

//! This mutex remains locked from initialization until the task finishes,
//! it's used as a trigger for waitForFinished.
QMutex mNotFinishedMutex;

//! Progress of this (parent) task alone
double mProgress;
//! Overall progress of this task and all subtasks
double mTotalProgress;
bool mShouldTerminate;
int mStartCount;

QWaitCondition mTaskFinished;

struct SubTask
{
SubTask( QgsTask *task, QgsTaskList dependencies, SubTaskDependency dependency )
Expand Down
3 changes: 1 addition & 2 deletions tests/src/python/test_qgsactionmanager.py
Expand Up @@ -154,8 +154,7 @@ def check_action_result(self, temp_file):
return output

@unittest.expectedFailure(platform.system() != 'Linux')
@unittest.skipIf(
os.environ.get('TRAVIS', '') == 'true', 'Test is flaky on Travis environment')
@unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', 'Test is flaky on Travis environment')
def testDoAction(self):
""" test running action """

Expand Down
1 change: 1 addition & 0 deletions tests/src/python/test_qgsserver_wms.py
Expand Up @@ -64,6 +64,7 @@ def wms_request_compare(self, request, extra=None, reference_file=None):

self.assertXMLEqual(response, expected, msg="request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8')))

@unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', 'Test is flaky on Travis environment')
def test_project_wms(self):
"""Test some WMS request"""
for request in ('GetCapabilities', 'GetProjectSettings', 'GetContext'):
Expand Down

0 comments on commit 9caa722

Please sign in to comment.