Skip to content

Commit

Permalink
[processing] Default to allowing background execution of algorithms
Browse files Browse the repository at this point in the history
Since the underlying issues with the Python bindings are now fixed,
in most cases we can safely default to allowing an algorithm to
run in a background thread!!

So now we make this the default, and require individual algorithms
which are NOT thread safe to declare this. This includes algorithms
which directly manipulate the current project or layers (such as
setting layer styles), alter the selections in layers, or which
rely on 3rd party libraries (for now, SAGA and GRASS algorithms
are marked as not thread safe... TODO - someone more familiar with
these libraries can investigate and remove the flag if appropriate).

Also models are marked as non-thread safe. TODO: only flag an
individual model as thread-unsafe if any of its child algorithms
report this flag.
  • Loading branch information
nyalldawson committed Jan 29, 2018
1 parent 070e137 commit a05d941
Show file tree
Hide file tree
Showing 117 changed files with 89 additions and 288 deletions.
Expand Up @@ -47,6 +47,8 @@ Constructor for QgsProcessingModelAlgorithm.

virtual QString helpUrl() const;

virtual Flags flags() const;


virtual bool canExecute( QString *errorMessage /Out/ = 0 ) const;

Expand Down
2 changes: 1 addition & 1 deletion python/core/processing/qgsprocessingalgorithm.sip.in
Expand Up @@ -44,7 +44,7 @@ Abstract base class for processing algorithms.
FlagSupportsBatch,
FlagCanCancel,
FlagRequiresMatchingCrs,
FlagCanRunInBackground,
FlagNoThreading,
FlagDeprecated,
};
typedef QFlags<QgsProcessingAlgorithm::Flag> Flags;
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -151,6 +151,10 @@ def icon(self):
def svgIconPath(self):
return QgsApplication.iconPath("providerGrass.svg")

def flags(self):
# TODO - maybe it's safe to background thread this?
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def tr(self, string, context=''):
if context == '':
context = self.__class__.__name__
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/CreateAttributeIndex.py
Expand Up @@ -27,6 +27,7 @@

from qgis.core import (QgsVectorDataProvider,
QgsFields,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingOutputVectorLayer)
Expand Down Expand Up @@ -56,6 +57,9 @@ def initAlgorithm(self, config=None):
self.tr('Attribute to index'), None, self.INPUT))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def name(self):
return 'createattributeindex'

Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/DefineProjection.py
Expand Up @@ -29,6 +29,7 @@
import re

from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterCrs,
QgsProcessingOutputVectorLayer)
Expand Down Expand Up @@ -65,6 +66,9 @@ def name(self):
def displayName(self):
return self.tr('Define current projection')

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/EliminateSelection.py
Expand Up @@ -33,6 +33,7 @@
QgsFeature,
QgsFeatureSink,
QgsGeometry,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingUtils,
QgsProcessingParameterVectorLayer,
Expand Down Expand Up @@ -67,6 +68,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.modes = [self.tr('Largest Area'),
self.tr('Smallest Area'),
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/ExecuteSQL.py
Expand Up @@ -28,6 +28,7 @@
from qgis.core import (QgsVirtualLayerDefinition,
QgsVectorLayer,
QgsWkbTypes,
QgsProcessingAlgorithm,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterString,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -62,6 +63,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterMultipleLayers(name=self.INPUT_DATASOURCES,
description=self.tr('Additional input datasources (called input1, .., inputN in the query)'),
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/ImportIntoSpatialite.py
Expand Up @@ -27,6 +27,7 @@

from qgis.core import (QgsDataSourceUri,
QgsFeatureSink,
QgsProcessingAlgorithm,
QgsVectorLayerExporter,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
Expand Down Expand Up @@ -76,6 +77,9 @@ def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH, self.tr('Drop length constraints on character fields'), False))
self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, self.tr('Create single-part geometries instead of multi-part'), False))

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def name(self):
return 'importintospatialite'

Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/RandomSelection.py
Expand Up @@ -32,6 +32,7 @@
from qgis.core import (QgsFeatureSink,
QgsProcessingException,
QgsProcessingUtils,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
Expand Down Expand Up @@ -59,6 +60,9 @@ def group(self):
def groupId(self):
return 'vectorselection'

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def __init__(self):
super().__init__()

Expand Down
Expand Up @@ -33,6 +33,7 @@
from qgis.core import (QgsFeatureRequest,
QgsProcessingException,
QgsProcessingUtils,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterEnum,
QgsProcessingParameterField,
Expand Down Expand Up @@ -65,6 +66,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.methods = [self.tr('Number of selected features'),
self.tr('Percentage of selected features')]
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/SelectByAttribute.py
Expand Up @@ -28,6 +28,7 @@
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsExpression,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -71,6 +72,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.i18n_operators = ['=',
'!=',
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/SelectByExpression.py
Expand Up @@ -26,6 +26,7 @@

from qgis.core import (QgsExpression,
QgsVectorLayer,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterExpression,
Expand All @@ -50,6 +51,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.methods = [self.tr('creating new selection'),
self.tr('adding to current selection'),
Expand Down
6 changes: 5 additions & 1 deletion python/plugins/processing/algs/qgis/SetRasterStyle.py
Expand Up @@ -29,7 +29,8 @@

from qgis.PyQt.QtXml import QDomDocument

from qgis.core import (QgsProcessingParameterRasterLayer,
from qgis.core import (QgsProcessingAlgorithm,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterFile,
QgsProcessingOutputRasterLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
Expand All @@ -50,6 +51,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.tr('Raster layer')))
Expand Down
6 changes: 5 additions & 1 deletion python/plugins/processing/algs/qgis/SetVectorStyle.py
Expand Up @@ -25,7 +25,8 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessingParameterFile,
from qgis.core import (QgsProcessingAlgorithm,
QgsProcessingParameterFile,
QgsProcessingParameterVectorLayer,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
Expand All @@ -46,6 +47,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Vector layer')))
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/SpatialIndex.py
Expand Up @@ -28,6 +28,7 @@
import os

from qgis.core import (QgsVectorDataProvider,
QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingOutputVectorLayer,
QgsProcessing)
Expand Down Expand Up @@ -57,6 +58,9 @@ def initAlgorithm(self, config=None):
[QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorPoint, QgsProcessing.TypeVectorLine]))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def name(self):
return 'createspatialindex'

Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/SpatialiteExecuteSQL.py
Expand Up @@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

from qgis.core import (QgsDataSourceUri,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterString)
Expand Down Expand Up @@ -58,6 +59,9 @@ def name(self):
def displayName(self):
return self.tr('SpatiaLite execute SQL')

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
Expand Down
6 changes: 5 additions & 1 deletion python/plugins/processing/algs/qgis/TruncateTable.py
Expand Up @@ -25,7 +25,8 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessingParameterVectorLayer,
from qgis.core import (QgsProcessingAlgorithm,
QgsProcessingParameterVectorLayer,
QgsProcessingOutputVectorLayer,
QgsProcessingException)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
Expand Down Expand Up @@ -53,6 +54,9 @@ def initAlgorithm(self, config=None):
self.tr('Input Layer')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Truncated layer')))

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def name(self):
return 'truncatetable'

Expand Down
5 changes: 5 additions & 0 deletions python/plugins/processing/algs/saga/SagaAlgorithm.py
Expand Up @@ -33,6 +33,7 @@
QgsProcessingException,
QgsMessageLog,
QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBoolean,
Expand Down Expand Up @@ -99,6 +100,10 @@ def groupId(self):
def shortHelpString(self):
return shortHelp.get(self.id(), None)

def flags(self):
# TODO - maybe it's safe to background thread this?
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

def defineCharacteristicsFromFile(self):
with open(self.description_file) as lines:
line = lines.readline().strip('\n').strip()
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -251,7 +251,7 @@ def on_complete(ok, results):

self.finish(ok, results, context, feedback)

if self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanRunInBackground:
if not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading):
# Make sure the Log tab is visible before executing the algorithm
self.showLog()

Expand Down
5 changes: 0 additions & 5 deletions src/3d/processing/qgsalgorithmtessellate.cpp
Expand Up @@ -31,11 +31,6 @@ QString QgsTessellateAlgorithm::displayName() const
return QObject::tr( "Tessellate" );
}

QgsProcessingAlgorithm::Flags QgsTessellateAlgorithm::flags() const
{
return QgsProcessingFeatureBasedAlgorithm::flags() | QgsProcessingAlgorithm::FlagCanRunInBackground;
}

QStringList QgsTessellateAlgorithm::tags() const
{