diff --git a/src/core/expression/qgsexpressioncontextutils.cpp b/src/core/expression/qgsexpressioncontextutils.cpp index e73711bf27e8..ced8986dcba1 100644 --- a/src/core/expression/qgsexpressioncontextutils.cpp +++ b/src/core/expression/qgsexpressioncontextutils.cpp @@ -994,10 +994,39 @@ QVariant QgsExpressionContextUtils::GetLayerVisibility::func( const QVariantList } bool isVisible = false; - Q_NOWARN_DEPRECATED_PUSH - QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), context, parent ); - Q_NOWARN_DEPRECATED_POP - if ( layer && mLayers.contains( layer ) ) + + // getMapLayer() will happily deadlock if multiple expression are evaluated at + // the same time from different threads + // see: https://github.com/qgis/QGIS/issues/53956 + // Searching by layer name/id in mLayer is safe and fast, let's do it first + + QgsMapLayer *layer = nullptr; + + if ( values.at( 0 ).type() == QVariant::String ) + { + const QString layerIdOrName { values.at( 0 ).toString() }; + + for ( const auto &layerPtr : std::as_const( mLayers ) ) + { + if ( layerPtr->id() == layerIdOrName || layerPtr->name() == layerIdOrName ) + { + layer = layerPtr; + break; + } + } + } + else + { + Q_NOWARN_DEPRECATED_PUSH + layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), context, parent ); + Q_NOWARN_DEPRECATED_POP + if ( ! mLayers.contains( layer ) ) + { + layer = nullptr; + } + } + + if ( layer ) { isVisible = true; if ( mScaleBasedVisibilityDetails.contains( layer ) && !qgsDoubleNear( mScale, 0.0 ) )