Code after the await keyword is executed in the main thread instead of the original thread.
HungryProton opened this issue · 5 comments
Godot version
4.1+
System information
Arch Linux - Vulkan (Forward+)
Issue description
When using await in a thread, the code after the await is executed in the main thread, instead of the original thread.
This bug only happens in 4.1 and above. It works fine 4.0.3 - stable.
(Apparently I got my builds mixed up, this also does not work in 4.0.3)
Steps to reproduce
Using this minimal function running in a thread as an example:
func run_in_thread() -> void:
print("Caller thread before await: ", OS.get_thread_caller_id())
await get_tree().create_timer(1.0).timeout
print("Caller thread after await: ", OS.get_thread_caller_id())In theory, this should print the same thread ID twice, but that's not the case, the second time it prints the main thread ID.
Also, it's not just a reporting issue, the main thread does freeze if you put a heavy workload after the await keyword.
Minimal reproduction project
-
Download this project:
await_thread_minimal_project.zip -
Or put this script on a node:
extends Node
var _thread: Thread
func _ready():
print("Main thread ID: ", OS.get_thread_caller_id())
_thread = Thread.new()
_thread.start(_run_in_thread)
func _exit_tree():
_thread.wait_to_finish()
func _run_in_thread() -> void:
print("Caller thread before: ", OS.get_thread_caller_id())
await get_tree().create_timer(1.0).timeout
print("Caller thread After: ", OS.get_thread_caller_id())
# Code from here will run on the main thread instead of the thread- Open the project.
- Press F5 (or run the minimal_scene.tscn).
- Check the console output, the last thread ID matches the main thread ID.
In 4.0.1 I get a different seemingly wrong result.
--- Debugging process started ---
Godot Engine v4.0.1.stable.official.cacf49999 - https://godotengine.org
Vulkan API 1.3.230 - Forward+ - Using Vulkan Device #0: AMD - AMD Radeon RX 580 Series (RADV POLARIS10)
Caller thread before: -6881540454091642859
Caller thread After: 5364107225503294706
--- Debugging process stopped ---
In 4.0, the main thread ID is not necessarily 1, it's the same issue.
I think my problem is related (Godot v4.1.stable.official [9704596] on Windows 11 Pro, Version 22H2, Build 22621.1778):
func _ready():
var semaphore = Semaphore.new()
semaphore.post()
var outside_index = 0
var task = func(index):
semaphore.wait()
print("%s" % index)
await get_tree().process_frame
semaphore.post()
var task_id = WorkerThreadPool.add_group_task(task, 2)
WorkerThreadPool.wait_for_group_task_completion(task_id)
get_tree().quit()
In the code above, the await even seems to prevent the semaphore.post(). With the await get_tree().process_frame statement, the program just hangs - most likely the semaphore.post() is not working. When I comment await get_tree().process_frame out, then I get the expected output
0
1
Is there any idea on how to work around this issue for the moment being?
Edit: Ok, I have a solution for my specific use case with await and signals, but it's rather messy and would be much more readable with a simple Semaphore. If anyone's interested ask and I provide it somewhere.
If anyone is facing the same problem, here is a possible solution to the problem.
var _thread: Thread
var _semaphore : Semaphore
func _ready():
_semaphore = Semaphore.new()
_thread = Thread.new()
_thread.start(_run_in_thread)
func _exit_tree():
_thread.wait_to_finish()
func _run_in_thread() -> void:
print("Caller thread before: ", OS.get_thread_caller_id())
get_tree().create_timer(1.0).timeout.connect(_semaphore.post)
_semaphore.wait()
print("Caller thread After: ", OS.get_thread_caller_id())