Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image resize crash when called from multiple C# threads #55528

Open
hhyyrylainen opened this issue Dec 1, 2021 · 1 comment
Open

Image resize crash when called from multiple C# threads #55528

hhyyrylainen opened this issue Dec 1, 2021 · 1 comment

Comments

@hhyyrylainen
Copy link

Godot version

3.4.stable.mono.official.206ba70f4

System information

Linux (Fedora), GLES3, AMD Radeon RX 6900 XT (SIENNA_CICHLID, DRM 3.42.0, 5.14.18-200.fc34.x86_64, LLVM 12.0.1)

Issue description

When calling Image.resize from multiple threads at once, for different image objects, I get the following crash:

ERROR: FATAL: Condition "!GDMonoUtils::is_thread_attached()" is true.
   at: free_instance_binding_data (modules/mono/csharp_script.cpp:1323)

=================================================================
	Native Crash Reporting
=================================================================
Got a UNKNOWN while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
	Native stacktrace:
=================================================================
	0xf2219d - /home/hhyyrylainen/bin/godot : 
	0xf22529 - /home/hhyyrylainen/bin/godot : 
	0xf14cff - /home/hhyyrylainen/bin/godot : 
	0xf2c180 - /home/hhyyrylainen/bin/godot : 
	0x7fc637440a20 - /lib64/libpthread.so.0 : 
	0x16ccf29 - /home/hhyyrylainen/bin/godot : _ZN14CSharpLanguage26free_instance_binding_dataEPv
	0x3785e36 - /home/hhyyrylainen/bin/godot : _ZN6ObjectD1Ev
	0x114f378 - /home/hhyyrylainen/bin/godot : 
	0x33d90a1 - /home/hhyyrylainen/bin/godot : 
	0x33f7a6c - /home/hhyyrylainen/bin/godot : _ZN18VisualServerWrapMT11thread_loopEv
	0x382cc18 - /home/hhyyrylainen/bin/godot : _ZN6Thread8callbackEPS_RKNS_8SettingsEPFvPvES4_
	0x3cd4140 - /home/hhyyrylainen/bin/godot : 
	0x7fc637436299 - /lib64/libpthread.so.0 : 
	0x7fc637206353 - /lib64/libc.so.6 : clone

=================================================================
	Telemetry Dumper:
=================================================================
Thread 0x7fc580ff9640 may have been prematurely finalized* Assertion at /root/mono-6.12.0.158/mono/utils/mono-threads.c:650, condition `info' not met, function:mono_thread_info_current, 
Process "/home/hhyyrylainen/bin/godot --path /home/hhyyrylainen/Projects/Thrive" terminated with exit code 0.

This issue has been intermittently happening but now with Godot 3.4 this has started to very consistently happen, though I guess this could also be correlated with how many images I'm loading at once. But now with the increased frequency of crashes and another person also reporting that they (perhaps unrelatedly) at least get a lot of the ERROR: FATAL: Condition "!GDMonoUtils::is_thread_attached()" is true. crashes, I decided I'd try to resolve this issue.

So I investigated the crashes related to Image loading with multiple threads (in order to not freeze a save load menu while loading preview screenshots) and found that if I add a lock around just the Image resize, I don't get the crash to happen. Without that lock, I can get a crash within a minute easily each time. Here's what I do with the Images after loading:

float aspectRatio = save.Screenshot.GetWidth() / (float)save.Screenshot.GetHeight();

if (save.Screenshot.GetHeight() > Constants.SAVE_LIST_SCREENSHOT_HEIGHT)
{
    // lock (ResizeLock)
    {
        save.Screenshot.Resize((int)(Constants.SAVE_LIST_SCREENSHOT_HEIGHT * aspectRatio),
            Constants.SAVE_LIST_SCREENSHOT_HEIGHT);
    }
}

If I uncomment that lock line, the crashes stop happening. Note that even then I'm still loading Images from files in background threads.

To me it is pretty weird that resizing an image from a background thread crashes when multiple are performed at once without a lock, but just loading multiple images at once works perfectly fine.

Steps to reproduce

  • Have a bunch of images loading at once in background threads (C# threads)
  • Try to resize all of the images as they get loaded in those Threads

Minimal reproduction project

No response

@DigitallyTailored
Copy link

Not sure if this helps at all but I have a separate thread in GDScript that reads image data to generate chunks. When calling .lock() and setting individual pixels from within C# in a different context I get the same error as above. It seems that any form of image manipulation in C# may be at risk when another image is being used in a separate thread.

As a temporary workaround I've ported that bit to GDScript and am calling it from inside C# in the meantime which seems to be working:

imageTexture.CreateFromImage((Image)helper.Call("get_chunk_heightmap_image", chunkPosition)); //GDScript method that returns a newly generated image

This is my first comment so apologies if it's not to spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants