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

"connect: Caller thread can't call this function" when a co-routine uses await internally #78149

Open
HungryProton opened this issue Jun 12, 2023 · 5 comments

Comments

@HungryProton
Copy link
Contributor

HungryProton commented Jun 12, 2023

Godot version

Godot v4.1.beta (2d6b880)

System information

Arch Linux - Vulkan (Forward+)

Issue description

I have an async function, using the keyword await, like so:

# PhysicsHelper

func execute(tasks) -> Array:
	# [...] Run the tasks

	await job_completed # Emited from _physics_process()

	return _results

And I have another script, that requires the result of this function, but from a thread:

func _run_threaded() -> void:
	var results = await physics_helper.execute( random_work )
        print(results)

This triggers an error in the debugger:

E 0:00:00:0496   connect: Caller thread can't call this function in this node (/root/minimal_scene/PhysicsHelper). Use call_deferred() or call_thread_group() instead.
  <C++ Error>    Condition "!is_accessible_from_caller_thread()" is true. Returning: (ERR_INVALID_PARAMETER)
  <C++ Source>   scene/main/node.cpp:3605 @ connect()

When removing await job_completed from the first script, the error does not occur.

I suspect this comes from the recent thread safety PRs: the async keyword uses the signal.connect() function internally, which is no longer allowed from a thread without using call_deferred.

Is this a regression, am I using it wrong, or is it by design?

Steps to reproduce

  • Create a Node with a function using the await keyword
  • Add the Node to the scene tree
  • Call this function from a thread

Minimal reproduction project

Minimal reproduction project: threaded_await_minimal_project.zip

  • Open the project.
  • Open the minimal_scene.tscn and run the project.
  • Check the debugger, you will see the error message there.

Additional information:

  • This project generates random PhysicsRayQueries and sends them to a PhysicsHelper class. This class runs the queries during the _physics_process before saving the results.

  • In the current state, you can see the await keyword (from the execute function in physics_helper.gd) is completely ignored. The threaded function returns immediately after calling execute.

  • The expected behavior is that it should wait for the signal job_completed before trying to print the results.

@akien-mga
Copy link
Member

CC @RandomShaper. #78000 might help :)

@HungryProton
Copy link
Contributor Author

Managed to work around the issue thanks to #78000, thanks!

@RandomShaper
Copy link
Member

As far as I can tell, such usage of signals is not safe. See #74404 (comment).

@git2013vb
Copy link

git2013vb commented Jul 16, 2023

Same kind of errors - not projects related - I have when I use vscode and the network/language_server/use_thread is set on
v4.1.stable.official [9704596]
Debian 11

  Caller thread can't call this function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7513/@RichTextLabel@7515). Use call_deferred() or call_thread_group() instead.
  Caller thread can't call this function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7513/@RichTextLabel@7515). Use call_deferred() or call_thread_group() instead.
  Caller thread can't call this function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7513/@RichTextLabel@7515). Use call_deferred() or call_thread_group() instead.
  Caller thread can't call this function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7513/@RichTextLabel@7515). Use call_deferred() or call_thread_group() instead.
  This function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7517/@Button@7528) can only be accessed from either the main thread or a thread group. Use call_deferred() instead.
  Caller thread can't call this function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7517/@Button@7528). Use call_deferred() or call_thread_group() instead.
  This function in this node (/root/@EditorNode@17637/@Control@697/@Panel@698/@VBoxContainer@706/@HSplitContainer@709/@HSplitContainer@717/@HSplitContainer@725/@VBoxContainer@726/@VSplitContainer@728/@PanelContainer@7498/@VBoxContainer@7499/@EditorLog@7529/@VBoxContainer@7517/@Button@7528) can only be accessed from the main thread. Use call_deferred() instead.```

@ZachAR3
Copy link

ZachAR3 commented Jul 19, 2023

I am getting the same issues, this is ridiculous that it made it to stable. Would this be considered "unsafe" and require calling deferred or will awaiting a separate threaded path be patched in addition to this? E.g:

await Task.Run(async () =>
		{
                 // Do stuff
                });

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

6 participants