Skip to content

WpfDrawingSettings is not thread safe #312

Description

@cz-dev-ge

Hi there,
first of all thank you for your great work.

Now to the issue:
We convert lots and lots of icons from SVG to XAML and do this in parallel. Unfortunately we had exception and I noticed that there is a HashSet inside WpfDrawingSettings which is changed during rendering. I did not except something like a settings container to be used as cache and thereby not being thread safe. As a workaround I create a new instance of WpfDrawingSettings for every execution. But it might be better to handle that cache differently and use the settings object as a simple read-only-settings thing.

From WpfDrawingContext:98

_registeredIds = settings[RegisteredIdKey] as HashSet<string>;
if (_registeredIds == null)
{
  _registeredIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
  settings[RegisteredIdKey] = _registeredIds;
}

Best regards,
G

PS: The stacktrace and some sample code:

Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
        at System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)
        at SharpVectors.Renderers.Wpf.WpfDrawingContext.RegisterId(String elementId)
        at SharpVectors.Renderers.Wpf.WpfPathRendering.RenderPath(WpfDrawingRenderer renderer)
        at SharpVectors.Renderers.Wpf.WpfRenderingHelper.RenderElement(ISvgElement svgElement)
        at SharpVectors.Renderers.Wpf.WpfRenderingHelper.RenderElementChildren(ISvgElement svgElement)
        at SharpVectors.Renderers.Wpf.WpfRenderingHelper.RenderElement(ISvgElement svgElement)
        at SharpVectors.Renderers.Wpf.WpfRenderingHelper.Render(ISvgDocument docElement)
        at SharpVectors.Renderers.Wpf.WpfDrawingRenderer.Render(ISvgDocument node)
        at SharpVectors.Converters.StreamSvgConverter.ProcessFile(Stream svgStream, Stream imageStream)
        at VectorImageMerger.Converter.Convert(FileInfo file, Dictionary`2 replacements, WpfDrawingSettings settings)
        at System.Linq.Parallel.PartitionedDataSource`1.ListContiguousIndexRangeEnumerator.MoveNext(T& currentElement, Int32& currentKey)
        at System.Linq.Parallel.PipelineSpoolingTask`2.SpoolingWork()
        at System.Linq.Parallel.SpoolingTaskBase.Work()
        at System.Linq.Parallel.QueryTask.BaseWork(Object unused)
        at System.Threading.Tasks.Task.Execute()
        --- End of inner exception stack trace ---
        at System.Linq.Parallel.QueryTaskGroupState.QueryEnd(Boolean userInitiatedDispose)
        at System.Linq.Parallel.AsynchronousChannelMergeEnumerator`1.MoveNextSlowPath()
        at System.Linq.Parallel.QueryOpeningEnumerator`1.MoveNext()
        at MyConverter.Converter.ConvertSvgToDrawingGroup(IEnumerable`1 files, Dictionary`2 replacements)
        at MyConverter.Converter.GenerateResourceDictionaryFile(DirectoryInfo vectorIconDirectory, FileInfo outputResourceFile, String resourcePrefix, String mappingFile, String[] namesToSkip)
        at MyConverter.Console.Program.Main(String[] args)
// IEnumerable<FileInfo> files
var settings = new WpfDrawingSettings { IncludeRuntime = false, IgnoreRootViewbox = false };
var convertedFiles = files
			.AsParallel()
			.Select( file => Convert( file, replacements, settings ) );

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions