PDFsharp & MigraDoc Foundation
https://forum.pdfsharp.net/

GlyphTypefaceCache multi-threading bug
https://forum.pdfsharp.net/viewtopic.php?f=3&t=3315
Page 1 of 1

Author:  seeker25 [ Wed Mar 09, 2016 10:20 pm ]
Post subject:  GlyphTypefaceCache multi-threading bug

Hello,

I am running PDF sharp latest version (PDFsharp-1_50-beta3b.zip) under Visual Studio 2015.

I seem to be running into a problem having two threads writing using PDFsharp.

Inside of XGlyphTypeface.cs, one thread is going in there and calling

GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface);, added in the glyphTypeface into the cache.

This is being done while the second thread is already past this point:

if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface))

meaning that it will also call GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface);,when it already exists inside of the Dictionary, thus causes an exception when trying to render a document.

An item with the same key has already been added. at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at PdfSharp.Fonts.OpenType.GlyphTypefaceCache.AddGlyphTypeface(XGlyphTypeface glyphTypeface)
at PdfSharp.Drawing.XGlyphTypeface.GetOrCreateFrom(String familyName, FontResolvingOptions fontResolvingOptions)
at PdfSharp.Drawing.XFont.Initialize()
at MigraDoc.Rendering.FontHandler.FontToXFont(Font font, PdfFontEncoding encoding)
at MigraDoc.Rendering.ParagraphRenderer.InitFormat(Area area, FormatInfo previousFormatInfo)
at MigraDoc.Rendering.ParagraphRenderer.Format(Area area, FormatInfo previousFormatInfo)
at MigraDoc.Rendering.TopDownFormatter.FormatOnAreas(XGraphics gfx, Boolean topLevel)
at MigraDoc.Rendering.FormattedCell.Format(XGraphics gfx)
at MigraDoc.Rendering.TableRenderer.FormatCells()
at MigraDoc.Rendering.TableRenderer.InitFormat(Area area, FormatInfo previousFormatInfo)
at MigraDoc.Rendering.TableRenderer.Format(Area area, FormatInfo previousFormatInfo)
at MigraDoc.Rendering.TopDownFormatter.FormatOnAreas(XGraphics gfx, Boolean topLevel)
at MigraDoc.Rendering.FormattedDocument.Format(XGraphics gfx)
at MigraDoc.Rendering.DocumentRenderer.PrepareDocument()
at MigraDoc.Rendering.PdfDocumentRenderer.PrepareDocumentRenderer(Boolean prepareCompletely)
at MigraDoc.Rendering.PdfDocumentRenderer.RenderDocument()

A bit of background info:

I am using GlobalFontSettings.FontResolver to resolve fonts, which creates and resolves these fonts. (public class EzFontResolver : IFontResolver) I am using WPF I believe as well.

I'm not sure if this is an issue with my implementation or the PDFsharp library itself with multiple threads/tasks. Any help would be appreciated.

My solution for this bug at the moment is to use all the fonts in the font resolver to render a dummy document in a single thread populating the dictionary before allowing multiple threads to render PDF documents.

Author:  Thomas Hoevel [ Thu Mar 10, 2016 9:09 am ]
Post subject:  Re: GlyphTypefaceCache multi-threading bug

Hi!

Thanks for the feedback. We need more "locks" in the code to prevent this problem.
We do have some locks already, but this case slips through. We'll add more locks with the next release.

Good to know you found a workaround.

Author:  mmmggg [ Wed Apr 13, 2016 10:07 am ]
Post subject:  Re: GlyphTypefaceCache multi-threading bug

Hello seeker25,

can you please share the code you use for rendering the dummy document in order to avoid the "An item with the same key has already been added" exception thrown when using PDFSharp in multithreaded app?

Thank you in advance.

Author:  seeker25 [ Fri Apr 22, 2016 9:11 pm ]
Post subject:  Re: GlyphTypefaceCache multi-threading bug

Code:

                //Setup for PdfSharp to use custom fonts.
                var fontResolver = EzFontResolver.Get;
                GlobalFontSettings.FontResolver = fontResolver;

fontResolver.AddFont("Courier New", XFontStyle.Regular, fontPath, true, true);

 var fontNames = new List<string>
                {
                    "courier new"
                };

   foreach (var fontName in fontNames)
                {
                    new XFont(fontName, 20, XFontStyle.Regular);

                    document.Styles.AddStyle(fontName, "Normal");
                    var style = document.Styles[fontName];
                    style.Font = new Font(fontName);

                    var styleName = fontName;
                    var para = document.AddSection().AddParagraph("H", styleName);
                    para.Format.Font.Bold = true;

                    para = document.AddSection().AddParagraph("H", styleName);
                    para.Format.Font.Italic = true;

                    para = document.AddSection().AddParagraph("H", styleName);
                    para.Format.Font.Bold = true;
                    para.Format.Font.Italic = true;

                }

                var pdfRenderer = new PdfDocumentRenderer { Document = document};
                pdfRenderer.RenderDocument();
                pdfRenderer.PdfDocument.Close();
                pdfRenderer.PdfDocument.Dispose();



This should populate the static dictionary.

Page 1 of 1 All times are UTC
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/