Race-condition when writing 32-bit png images with text in parallel.
See original GitHub issuePrerequisites
- I have written a descriptive issue title
- I have verified that I am running the latest version of ImageSharp
- I have verified if the problem exist in both
DEBUG
andRELEASE
mode - I have searched open and closed issues to ensure it has not already been reported
ImageSharp version
3.0.0-alpha.0.73
Other ImageSharp packages and versions
SixLabors.ImageSharp.Drawing: 1.0.0-beta15.3, SixLabors.Fonts: 1.0.0-beta19.5
Environment (Operating system, version and so on)
Windows 10, 22H2, Build 19045.2486
.NET Framework version
.NET 7
Description
In unit test I experienced that when running test locally, the text in images would sometimes move a tiny bit, but only when running the tests in parallel, which made me think there was a race-condition somewhere.
Below I have created the smallest reproducing example I could come up with and commented with what changes removes what looks like a race-condition to me.
To repeat to conditions here:
- Running in parallel
- Using
Rgba32
- Writing some text with a space and some character, e.g.
" A"
. - Saving to gif, tga, or png.
Steps to Reproduce
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
// Works for: single thread
// Fails for: two threads
const int NumberOfThreads = 2;
Parallel.ForEach(Enumerable.Range(0, NumberOfThreads), _ =>
{
var imageLength0 = Generate();
var imageLength1 = Generate();
if (imageLength0 != imageLength1)
throw new InvalidOperationException($"Expected {imageLength0} to equal {imageLength1}");
});
static long Generate()
{
using var memoryStream = new MemoryStream();
// Works for: Rgb24
// Fails for: Rgba32
using var image = new Image<Rgba32>(30, 15);
// Works for: " ", " ", "A" or "AA"
// Fails for: " A", "A "
const string Text = " A";
image.Mutate(x => x.DrawText(Text, SystemFonts.CreateFont("Arial", 15), Color.Black, new PointF(0, 0)));
// Works for bmp, jpeg
// Fails for png, tga, gif
image.SaveAsPng(memoryStream);
return memoryStream.Length;
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.0-alpha.0.73" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15.3" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta19.5" />
</ItemGroup>
</Project>
Images
No response
Issue Analytics
- State:
- Created 8 months ago
- Comments:14 (7 by maintainers)
Top Results From Across the Web
Is it possible to have a race condition for a write-only ...
Although on the surface the answer would seem to be no, there are no race conditions, the answer is a bit more nuanced....
Read more >C++ Tutorial: Multi-Threaded Programming - C++ Class ...
We now have a problem: a race condition. Imagine two producers both calling into put() at the same time.
Read more >Parallel Thread Execution 8.2
One set of local 32-bit registers per processor,. A parallel data cache or shared memory that is shared by all scalar processor cores...
Read more >Parallel computing
Parallel computing is a type of computation in which many calculations or processes are carried out simultaneously. Large problems can often be divided...
Read more >Race condition not seen while two scripts write to a same file
Simply, the echo command triggers one write syscall which is atomic. Note that write doesn't guarantee to write all bytes it is given, ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Some more findings.
Removing
ascender -= metric.TopSideBearing * scaleY;
from https://github.com/SixLabors/Fonts/commit/39773e680338b229cc285b52a3ba97ef9bf63182 fixes my problem and all SixLabor.Fonts test at that commit pass.Similarly removing
ascender -= tsbOffset * scaleY;
from current main fixes my problem and all SixLabor.Fonts test at that commit pass.Sure! See the difference in the amount of vertical space above the text.