Close Thread Safely Without Waiting For It To Finish

Godot Version

4.5.1

Question

I am working on an app that uses a lot of multithreading for its primary use case.

The user can start the ‘task’ with an arbitrary number of threads, which involves having each thread run a simple script where it looks at a folder on the users file system and reads the folders and files and returns data representing it.

(Dumbed-down equivalent for examples sake)

func search(folder : String) -> PackedStringArray:
	var results : PackedStringArray = []
	results.append(DirAccess.get_files_at(folder))
	results.append(DirAccess.get_directories_at(folder))
	return results

This works fine, the issue is since it relies on a lot of reading from disk, if multiple large directories are read from at once the read speed on the disk / drive gets maxed out and therefor each thread will be waiting until it gets given its information.

So if the user then tries to stop the process (Which I allow them to do without closing the app) then they need to wait for each one to finish, which will take an unpredictable amount of time.

(How this is currently done)

# 'all_threads_idle' returns true if every thread in 'threads'
# is not started
# It is inside a while to make sure it only continues if
# all threads are finished properly.
while not all_threads_idle:
	for t : Thread in threads:
		if t.is_started():
			while t.is_alive():
				await get_tree().process_frame
			t.wait_to_finish()

If I just try to wait for each thread to finish the app will hang instead of displaying the loading screen I show before and while running this, and if I try to free the threads without finishing them I get warnings about not properly closing the threads.
Leaving me to wait for the threads to finish despite not using the return values as the task is being abandoned.

Is there a way to safely stop the threads without waiting (Atleast waiting as long)?

The Godot editor is seemingly able to do this, as if you force-close the app during this (On any time while threads are active) no warnings appear about thread leaks / issues in the console and the app is closed near-immediately, so there seems to be a way to safely force-stop a thread quickly before freeing it; how can this be done manually without just closing / crashing the app?

Thanks.

Signal the thread to quit via a flag.

How do you do this?
Which flag do you use and how? Looking at the Thread docs doesn’t seem to mention this.

Thanks.

Just make some boolean property in the same class the thread function is defined so thread can access it.

var cancel := false
var thread: Thread 

func thread_code():
	while not cancel:
		# do some work

func kill_thread():
	cancel = true
	thread.wait_to_finish()

The point is, the thread needs to quit itself. It can’t be forced from the outside, just signaled to do it. Otherwise your program cannot guarantee its state, resources and stack frames may leak and mutexes may be left locked forever. Most languages don’t allow thread termination in this way, standard C++ included.

1 Like

Thanks! A shame you can’t stop them suddenly - Makes me curious how Godot does it, as I said it can do it on the fly when stopping the project from the editor - but I was able to use an existing variable which started this stopping process to determine when to cancel early.

Though this doesn’t stop instantly as when the flag is set threads awaiting read responses will remain paused; but now they will stop doing future reads which makes them stop faster.

Thanks.

You need to organize/breakdown your thread code so it checks the flag frequently.

The project is run as a separate process which owns all threads. So when that process is killed, the OS automatically cleans up everything the process allocated, including its threads.