Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Help Waiting For Thread to Finish Before Returning

Discussion in 'Scripting' started by xjjon, Jul 11, 2016.

  1. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    593
    I am using the C# Thread library to complete some pathfinding jobs. Something like this

    Code (csharp):
    1.  
    2.  public Vector3 GetPath(Vector3 start, Vector3 end){
    3.    
    4.   Vector3 path;
    5.    
    6.   thread = new Thread(() => {
    7.   path = PathFinder.FindPath(start, end);
    8.   });
    9.    
    10.    
    11.   thread.Start();
    12.    
    13.    
    14.   return path;
    15.   }
    16.  
    17.  
    So as you can see, the path is found in the created thread.
    And I wish to return it after the thread is done.
    However, the function always returns right after Thread.Start() is called, so path never has a value.

    Doesn't seem like you can use Tasks in Unity. I am not sure if using co-routines and yielding is a good solution, as it's still on the main thread?

    How can I wait until it is finished? Thanks.
     
  2. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    Is FindPath touching the Unity API? Because the API isn't thread safe so if it is you will have to use coroutines.

    If not then you will want to invoke the thread start from a coroutine and have that coroutine wait for the thread to finish before calling some event to notify that thet path is finished. In pseudo c# -

    Code (CSharp):
    1.  
    2.  
    3.  
    4.     IEnumerator ThreadCallingRoutine(Action<Vector3> foundHandler, Vector3 start, Vector3 end)
    5.     {
    6.  
    7.         Vector3 path;
    8.  
    9.         Thread thread = new Thread(() => {
    10.             path = PathFinder.FindPath(start, end);
    11.         });
    12.  
    13.  
    14.         thread.Start();
    15.         while(thread.IsAlive)
    16.         {
    17.             yield return null;
    18.         }
    19.         //
    20.  
    21.  
    22.         foundHandler(path);
    23.     }
    24.  
    25.  
    26.     void PathFound(Vector3 path)
    27.     {
    28.         // the path has been found so something
    29.     }
    Then somewhere just call :

    Code (CSharp):
    1.  StartCoroutine(ThreadCallingRoutine(PathFound, start, end));
    You will just need to some logic to wait for PathFound to be called.
     
    xjjon likes this.
  3. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    593
    Thanks, I have separated the pathfinding into separate threads.

    However I get some hiccup in my game when there is more than two enemies (i.e. 2+ threads running).

    The enemies all move on the same turn, however I don't call all the move functions at the same time, as there's a quick yield between each call.

    I am just using A* on a 2D array, with not too many nodes (100), so it should not be too taxing on the CPU, but I still get a hiccup with each turn.
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Don't spin up a different thread for every pathfinding request.

    We have a single thread that gets requests passed to it. The thread does all the processing and then marshals the result back to the main thread by handing it a MonoBehaviour singleton that checks its list of results in Update in order to actually do something in Unity's main thread.

    Aside - why does your pathfinding only return a single Vector3?
     
    xjjon likes this.
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Just like every other threading solution, you have to manually wait until the thread is done. A simple way in Unity is to have the thread expose an isDone property. Then you use a coroutine with while (!isDone) yield return null.

    You really don't want to wait until a thread is done before returning. You would need to block the main thread. Might as well simply run the code on the main thread in that case.
     
    xjjon likes this.
  6. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    593
    Thank you, I put all the path finding on a single thread and implemented a job queue so the pathfinder computes them FIFO order. Then I return them to the main thread based on an entityID. This seems to work well as it does not seem to have any hiccups in the game anymore.

    And to answer your question, the pathfinding computes a list of points to the target, but it's a turned based game, so only the 'next' step is needed. So I only return the next step instead of the entire path.