godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.46k stars 21.27k forks source link

GodotSynchronizationContext Task Send and Post always run on main thread? #83932

Open ljgdsq opened 1 year ago

ljgdsq commented 1 year ago

Godot version

4.1

System information

win10 godot4.1-latest

Issue description

var Context = GodotSynchronizationContext.Current;
GD.Print($"main thread id : {Thread.CurrentThread.ManagedThreadId}");
    Task.Run(() =>
        {
            GD.Print($"thread id : {Thread.CurrentThread.ManagedThreadId}");
            Context.Send((obj) =>
            {
                GD.Print($"Send thread id : {Thread.CurrentThread.ManagedThreadId}");
            }, null);
            Context.Post((obj) =>
            {
                GD.Print($"Post thread id : {Thread.CurrentThread.ManagedThreadId}");
            }, null);
        }); 

Steps to reproduce

GodotSynchronizationContext Post run on main thread , is this a bug? run the code output

main thread id : 1 thread id : 4 Send thread id : 1 Post thread id : 1

Minimal reproduction project

"N/A"

ljgdsq commented 1 year ago

i think the post should run on child thread . am i correct?

raulsntos commented 1 year ago

The purpose of a SynchronizationContext is to queue work to a context. Note that this unit of work is queued to a context rather than a specific thread, what thread is used depends on the SynchronizationContext implementation.

In the case of the GodotSynchronizationContext, the goal is to queue work to be synchronized with the Godot main thread, so as you found out the queued unit of work is executed in Godot's main thread. This synchronization context is used to queue async continuations to ensure usage of Godot API works as expected.

Both the Send and Post methods queue unit of work to the context, so the work will be executed in the Godot main thread. The difference between the two methods is that the Send method is blocking,[^1] whereas the Post method is not.[^2]

You can read more about synchronization contexts in the article It's All About the SynchronizationContext in the MSDN Magazine.

[^1]: This means that the code will wait until the unit of work is finished executing before continuing. [^2]: Technically Post is not necessarily asynchronously and some SynchronizationContext implementations implement it synchronously. In Godot it's asynchronous.