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

Thread remains in active state when function has finished #7235

Closed
mihai-dragan opened this issue Dec 2, 2016 · 16 comments · Fixed by #53455
Closed

Thread remains in active state when function has finished #7235

mihai-dragan opened this issue Dec 2, 2016 · 16 comments · Fixed by #53455

Comments

@mihai-dragan
Copy link

Windows 7 64 bit - Godot v2.1.1 stable

Started a thread defined as global variable to my script:
var handler = Thread.new()
like this (from _process):
handler.start(self, "_handle_comm", connection)
At the end of _handle_comm function I print a message:
print("exit handler")

I see this message printed to stdout, but when I check the thread with is_active() it returns true.
In the output console (stdout/err) I see this message:
ERROR: Reference to a Thread object object was lost while the thread is still running..
At: core\bind\core_bind.cpp:2376

@leonkrause
Copy link
Contributor

When the thread is done, call wait_to_finish() on it.
That function will wait until the thread's done and set it to inactive, or just set it to inactive immediately if it's already finished

@mihai-dragan
Copy link
Author

Thanks, this workaround is good.

@mihai-dragan
Copy link
Author

Just realized that the message about the lost Thread object is printed only when you exit the application.

@leonkrause
Copy link
Contributor

It's not a workaround, if you fork off into a thread, you have to join it back into the main thread later to have it deallocated. That's what wait_to_finish does.

If you don't care about the return value, you can use something like thread.call_deferred( 'wait_to_finish' ) as the last call of the thread to take care of it easily

@mihai-dragan
Copy link
Author

Seems a bit pointless to have to wait for a thread. I mean you start a thread because you don't want to wait...

@bojidar-bg
Copy link
Contributor

Well, sometimes you need the return value from said thread, and might want to hang while it finishes rather than not.
That being said, @eska014's """workaround""" is pretty simple anyway:

func _thread_func(params):
  var done = do_stuff(with(params))
  var result = do_more_stuff(with(done))
  mutex.lock(); value = result; mutex.unlock()
  # All done, updated on main thread, better to tell it to close the nonmain thread:
  params.thread.call_deferred("wait_to_finish") # Execute on idle main thread

@bojidar-bg
Copy link
Contributor

Ahem. Is there something we should do about this, or should we leave it as-is?

@ghost
Copy link

ghost commented Apr 8, 2018

First of all thank you for your report and sorry for the delay.

We released Godot 3.0 in January 2018 after 18 months of work, fixing many old issues either directly, or by obsoleting/replacing the features they were referring to.

We still have hundreds of issues whose relevance/reproducibility needs to be checked against the current stable version, and that's where you can help us.
Could you check if the issue that you described initially is still relevant/reproducible in Godot 3.0 or any newer version, and comment about it here?

For bug reports, please also make sure that the issue contains detailed steps to reproduce the bug and, if possible, a zipped project that can be used to reproduce it right away. This greatly speeds up debugging and bugfixing tasks for our contributors.

Our Bugsquad will review this issue more in-depth in 15 days, and potentially close it if its relevance could not be confirmed.

Thanks in advance.

Note: This message is being copy-pasted to many "stale" issues (90+ days without activity). It might happen that it is not meaningful for this specific issue or appears oblivious of the issue's context, if so please comment to notify the Bugsquad about it.

@Toshiwoz
Copy link
Contributor

Hey,
I do have this same issue, but I'm thinking that maybe it will be solved with this(?):
#9339

And actually, I am not understanding how the wait_to_finish function can work without freezing.

@Zylann
Copy link
Contributor

Zylann commented Nov 10, 2018

I also run into this as well in Godot 3.1 alpha2, my thread function finishes to execute, but is_active is still returning true. The only way to make it go false is to call wait_to_finish(), but it will potentially hang the application if the function was actually still running. There is no way to know...
For now the workaround I use is to emit a deferred signal at every exit point of the function, a bit like #9339 proposes to have built-in.

@Xrayez
Copy link
Contributor

Xrayez commented Jan 8, 2020

I've been working on adding completed thread signal feature for #9339, stumbled upon similar inconveniences: #34862 (comment). I haven't pushed the described changes because seems like the issue is mostly resolved as you could always ensure that the thread is joined with wait_to_finish upon completion which might be just an explicit way to deal with threads, even if it takes several lines of repeating code as they say.

@Calinou
Copy link
Member

Calinou commented May 15, 2021

@mihai-dragan Can you (or anyone else) still reproduce this bug in Godot 3.3 or any later release?

If yes, please ensure that an up-to-date Minimal Reproduction Project (MRP) is included in this report (a MRP is a zipped Godot project with the minimal elements necessary to reliably trigger the bug). You can upload ZIP files in an issue comment with a drag and drop.

@Setadokalo
Copy link
Contributor

Setadokalo commented May 29, 2021

I can confirm this still occurs - I have a heavy benchmarking task triggerable by a GUI button, and thus made it off thread and was originally checking if the thread was still is_active() (to prevent running the benchmark twice at the same time), but it wouldn't let me run the benchmark a second time - quite a bit of debugging later I finally realized is_active() never stops being true. All done on 3.3.2.

@tvardero
Copy link

tvardero commented Jun 10, 2021

I also can confirm it still occurs in v3.3.2 stable official.
In my case i have procedural world generation and after managing chunks threads remains active after method being finished (also printed "done" in the end of the method, but thread.is_active() is true). Calling for wait_to_finish() softlocks the project, because thread never finishes.

@tvardero
Copy link

tvardero commented Jun 10, 2021

MInimal reproduction project:

(just create a simple Node.tscn and attach this script to it and run)

extends Node

var my_thread: Thread = Thread.new()

func _ready() -> void:
	some_method()
	
	var timer: Timer = Timer.new()
	add_child(timer)
	timer.connect("timeout", self, "call_thread")
	timer.start(3)

func some_method(_args: Array = []) -> void:
	print("done")

func call_thread() -> void:
	my_thread.start(self, "some_method", [])

image
image

@Banderi
Copy link

Banderi commented May 26, 2023

The workaround of using call_deferred("wait_to_finish") as the last thread instruction works, however as a minor annoyance, to be kept in mind is that if one has multiple parts of code where one calls wait_to_finish (e.g. an external attempt to kill the thread) the engine will complain about it. Potentially flooding the log on thread-heavy applications:
image
Another method is to relay a variable to the main thread signaling that the thread is done and wants to be joined, e.g.:

var is_stopping = false
func _process(delta):
	if is_stopping:
		thread.wait_to_finish()
		is_stopping = false

func manual_stop():
	if is_stopping == true:
		return
	thread.wait_to_finish()
	is_stopping = false

and:

func _THREAD_SUBROUTINE(args):
	# ...
	# ... does thread things ...
	# ...

	# cleanup thread
	is_stopping = true

@YuriSizov YuriSizov added this to the 4.0 milestone Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet