+1 vote

Hello,
i have a custom made path finding algorithm, and since it takes a lot of resources i want it to run in background with a thread.
To avoid the units to stand still too much time the algorithm interrupt himself after a few seconds, it tells what´s the best path up to a certain point, and then evaluate if it is necessary to start another path-finding research to reach the actual target. And so on in a loop.
This is the basic code:

var target
func find_path(start, end):
    target=end
    if not thread.is_active():
        thread.start(self, "calculate", start)
        evaluate_path(thread.wait_to_finish())
    else:
        print("thread still active")


func evaluate_path(p):
    if p[p.size()-1]==target:
        unit.start_moving_along(p)
        print("path found")
    elif 0.5*(p[0]-target).lenght()>(p[p.size()-1]-target).length()
        unit.start_moving_along(p)
        print("getting close, continue from the last point of path")
        find_path(p[p.size()-1],target)
    else:
        print("There is no available path")

func calculate(start):
   var path=PoolVector2Array() 
   path=do_the real_calculations(start, target)
   return path

It works fine if the target is reached in the first loop (meaning the sequence of find_path=> calculate=>evaluate).
But for some reason it freeze in the following ones: basically every time it prints *path not found yet* or *getting close* it looks like it´s not working on the second thread anymore, because I can no more move the camera and do other in game stuff until the calculation is finished.
Can you help me understand why?
The thread is correctly closed because it doesnt print *thread still active*


EDIT:
I believe the waittofinish() function push another function into the thread: writing evaluate_path(thread.wait_to_finish())mean that the evaluate function is started into the secondary thread as soon as the pathfinding is finished, and since the evaluate_function is linked to the unit movement, and the unit movement is linked to all the game, all the game start running on the secondary thread, therefore it freeze because the next loop of pathfinding is being processed in the same thread of the game.

Can somebody confirm this?
If yes, how the hell can i make this simple sequence to work?
1-get the start and ending point
2-start a thread
3-run path finding algorithm on secondary thread
4-background calculation reach an end, close the thread
5-examine results in main thread,decide if to start again from point 1

in Engine by (1,432 points)
edited by

1 Answer

+5 votes
Best answer

You start a thread and immediately call thread.wait_to_finish(). It lock your main thread until thread is done with its job.

Have a look at thread example in Godot Asset Lib:
https://github.com/godotengine/godot-demo-projects/blob/3.0-d69cc10/misc/threads/thread.gd

You need to do something like this in your worker thread

call_deferred("_bg_load_done")
return tex # return it

The trick is: _bg_load_done will be done in main thread, not worker thread. It's pretty important.

In _bg_load_done (or whatever name you use) main thread will wait_to_finish

func _bg_load_done():
    # Wait for the thread to complete, get the returned value
    var tex = thread.wait_to_finish()
by (2,264 points)
selected by

THANK YOU!
I finally understood how the waittofinish() function works, it´s quite tricky!
For anybody that is looking for the same problem, you basically have to call the function that finishes the thread at the end of the thread function using calldeferred, and in that ending function immediatly call waitto_finish() on the thread.
Something like this:

var thread=Thread.new()

func starting_function()
 thread.start(self, "thread_function", any_value)

func thread_function(value):
 var r=do_your_stuff()
 call_deferred("ending_function")
 return r  #this value will be passed to ending_function

func ending_function():
 var result=thread.wait_to_finish()  #result=r
 do_stuff_with_result()

If you don't need the return value, a quick way to do the same thing would be to call thread.call_deferred("wait_to_finish")

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.