Skip to content

Commit

Permalink
Add QgsThreadingUtils::runOnMainThread
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Sep 11, 2018
1 parent e192e18 commit 6ab1aa7
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 48 deletions.
20 changes: 3 additions & 17 deletions src/analysis/vector/geometry_checker/qgsgeometrycheck.cpp
Expand Up @@ -19,21 +19,7 @@
#include "qgsfeaturepool.h"
#include "qgsvectorlayer.h"
#include "qgsreadwritelocker.h"

template <typename Func>
void runOnMainThread( const Func &func )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
func();
else
QMetaObject::invokeMethod( qApp, func, Qt::BlockingQueuedConnection );
#else
func();
#endif
}
#include "qgsthreadingutils.h"

QgsGeometryCheckerContext::QgsGeometryCheckerContext( int _precision, const QgsCoordinateReferenceSystem &_mapCrs, const QMap<QString, QgsFeaturePool *> &_featurePools, const QgsCoordinateTransformContext &transformContext )
: tolerance( std::pow( 10, -_precision ) )
Expand All @@ -50,7 +36,7 @@ const QgsCoordinateTransform &QgsGeometryCheckerContext::layerTransform( const Q
if ( !mTransformCache.contains( layer ) )
{
QgsCoordinateTransform transform;
runOnMainThread( [this, &transform, layer]()
QgsThreadingUtils::runOnMainThread( [this, &transform, layer]()
{
QgsVectorLayer *lyr = layer.data();
if ( lyr )
Expand All @@ -70,7 +56,7 @@ double QgsGeometryCheckerContext::layerScaleFactor( const QPointer<QgsVectorLaye
if ( !mScaleFactorCache.contains( layer ) )
{
double scaleFactor = 1.0;
runOnMainThread( [this, layer, &scaleFactor]()
QgsThreadingUtils::runOnMainThread( [this, layer, &scaleFactor]()
{
QgsVectorLayer *lyr = layer.data();
if ( lyr )
Expand Down
Expand Up @@ -14,24 +14,10 @@ email : matthias@opengis.ch
***************************************************************************/

#include "qgsvectordataproviderfeaturepool.h"
#include "qgsthreadingutils.h"

#include "qgsfeaturerequest.h"

template <typename Func>
void runOnMainThread( const Func &func )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
func();
else
QMetaObject::invokeMethod( qApp, func, Qt::BlockingQueuedConnection );
#else
func();
#endif
}

QgsVectorDataProviderFeaturePool::QgsVectorDataProviderFeaturePool( QgsVectorLayer *layer, bool selectedOnly )
: QgsFeaturePool( layer )
, mSelectedOnly( selectedOnly )
Expand Down Expand Up @@ -77,15 +63,15 @@ bool QgsVectorDataProviderFeaturePool::addFeature( QgsFeature &feature, Flags fl
res = lyr->dataProvider()->addFeatures( features );
};

runOnMainThread( addFeatureSynchronized );
QgsThreadingUtils::runOnMainThread( addFeatureSynchronized );

if ( !res )
return false;

feature.setId( features.front().id() );
if ( mSelectedOnly )
{
runOnMainThread( [ this, feature ]()
QgsThreadingUtils::runOnMainThread( [ this, feature ]()
{
QgsVectorLayer *lyr = layer();
if ( lyr )
Expand Down Expand Up @@ -115,14 +101,14 @@ bool QgsVectorDataProviderFeaturePool::addFeatures( QgsFeatureList &features, Qg
res = lyr->dataProvider()->addFeatures( features );
};

runOnMainThread( addFeatureSynchronized );
QgsThreadingUtils::runOnMainThread( addFeatureSynchronized );

if ( !res )
return false;

if ( mSelectedOnly )
{
runOnMainThread( [ this, features ]()
QgsThreadingUtils::runOnMainThread( [ this, features ]()
{
QgsVectorLayer *lyr = layer();
if ( lyr )
Expand Down Expand Up @@ -156,7 +142,7 @@ void QgsVectorDataProviderFeaturePool::updateFeature( QgsFeature &feature )
}
changedAttributesMap.insert( feature.id(), attribMap );

runOnMainThread( [this, geometryMap, changedAttributesMap]()
QgsThreadingUtils::runOnMainThread( [this, geometryMap, changedAttributesMap]()
{
QgsVectorLayer *lyr = layer();
if ( lyr )
Expand All @@ -172,7 +158,7 @@ void QgsVectorDataProviderFeaturePool::updateFeature( QgsFeature &feature )
void QgsVectorDataProviderFeaturePool::deleteFeature( QgsFeatureId fid )
{
removeFeature( fid );
runOnMainThread( [this, fid]()
QgsThreadingUtils::runOnMainThread( [this, fid]()
{
QgsVectorLayer *lyr = layer();
if ( lyr )
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -946,6 +946,7 @@ SET(QGIS_CORE_HDRS
qgstextlabelfeature.h
qgstextrenderer.h
qgstextrenderer_p.h
qgsthreadingutils.h
qgstracer.h
qgstranslationcontext.h

Expand Down
64 changes: 64 additions & 0 deletions src/core/qgsthreadingutils.h
@@ -0,0 +1,64 @@
/***************************************************************************
qgsthreadingutils.h
--------------------------------------
Date : 11.9.2018
Copyright : (C) 2018 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSTHREADINGUTILS_H
#define QGSTHREADINGUTILS_H

#define SIP_NO_FILE

#include "qgis_core.h"

#include <QThread>

/**
* \ingroup core
* Provides threading utilities for QGIS.
*/
class CORE_EXPORT QgsThreadingUtils
{
public:

/**
* Guarantees that \a func is executed on the main thread. If this is called
* from another thread, the other thread will be blocked until the function
* has been executed.
* This is useful to quickly access information from objects that live on the
* main thread and copying this information into worker threads. Avoid running
* expensive code inside \a func.
*
* \note Only works with Qt >= 5.10, earlier versions will execute the code
* in the worker thread.
*
* \since QGIS 3.4
*/
template <typename Func>
static void runOnMainThread( const Func &func )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
func();
else
QMetaObject::invokeMethod( qApp, func, Qt::BlockingQueuedConnection );
#else
func();
#endif
}

};


#endif
12 changes: 2 additions & 10 deletions src/core/qgsvectorlayerutils.cpp
Expand Up @@ -24,6 +24,7 @@
#include "qgsrelationmanager.h"
#include "qgsfeedback.h"
#include "qgsvectorlayer.h"
#include "qgsthreadingutils.h"

QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
{
Expand Down Expand Up @@ -516,16 +517,7 @@ std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSour
}
};

#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
getFeatureSource();
else
QMetaObject::invokeMethod( qApp, getFeatureSource, Qt::BlockingQueuedConnection );
#else
getFeatureSource();
#endif
QgsThreadingUtils::runOnMainThread( getFeatureSource );

return featureSource;
}
Expand Down

0 comments on commit 6ab1aa7

Please sign in to comment.