Easy Threading – Unity asset store plugin

Work with multiple threads easily!

Get it HERE, Link to unity forums post (For support): HERE

To build a truly responsive Unity game, you must keep long-running operations off of the main thread, and be careful to avoid blocking the main thread. This means you will need to execute various operations in the background. Unity’s coroutines are ALWAYS executed on the main Thread Executing threads in the background implies carefully go back to the main thread when you have to manipulate Unity’s objects. Piece of cake with this package, just use this sentence:

Task.RunInMainThread(SomeFunction);

SomeFunction is guaranteed to be executed in the main thread Of course i’s possible to use lambda expressions:

Task.RunInMainThread(()=> 
{ 
    // This code will execute in the main thread );
}

But this asset also makes working with threads a pleasant experience: To create a thread just use the following syntax:

Task.Run (DoSomeWorkOnABackgroundThread);

Creating a thread that returns some value (an integer in this example, but it can be any type, including a custom class):

Task<int>.Run (CalculateSomeIntegerInTheBackground);

Of course you will want to receive the integer:

Task<int>.Run (CalculateSomeIntegerInTheBackground).ContinueWith(ThisFunctionReceivesTheIntegerAsParameter);

Or, maybe, you need to show that integer to the player (the function receiving it must be executed in the main thread):

Task<int>.Run (CalculateSomeIntegerInTheBackground).ContinueInMainThreadWith(CheckTaskResult);

The function in “ContiuneWith” or “ContinuneInMainThreadWith” will receive the Task object and will be able to check itsĀ final state of the task (Succeeded, Aborted or Faulted) and its result (in case of tasks with parameters):

void CheckTaskResult(Task<int> t) 
{ 
   if (t.IsFaulted) 
   { 
      log.text+= "Error executing task: " + t.Exception; 
   } 
   else 
   { 
      log.text+= "Tasks executed successfully, result: " + t.Result; 
   } 
}

It is possible to abort the execution of a task by invoking the method task.AbortThread, it will raise the Exception System.Threading.ThreadAbortException on the task code and set the task final state to Aborted:

m_taskToAbort = Task.Run (() => 
{ 
   try 
   { 
      // [...] Code that supports to be aborted 
   } 
   catch(System.Threading.ThreadAbortException tae) 
   { 
      Debug.Log ("Thread was aborted before finishing"); 
      throw tae; // rethrow if you want the task to be set as aborted 
   } 
}); 

m_taskToAbort.ContinueInMainThreadWith ((t) => 
{ 
   if(t.IsAborted) 
      log.text+= "Thread was aborted before finishingn"; 
   else 
      log.text+= "Thread finished without being abortedn"; 
}); 
// [...] 
m_taskToAbort.AbortThread();

It is also possible to wait for a task to finish by blocking the current thread:

Task.Run (() => 
{ 
   // [...] Code to be executed in auxiliary thread, and launches a second auxiliary thread 
   Task t = Task.Run (() => 
   { // [...] Code to be executed in auxiliary thread 
      Debug.Log("Task is finished, parent thread will be unblocked"); 
   }); 
   // [...] And waits for that thread to finish 
   Debug.Log("Will wait for task"); 
   t.Wait (); 
   Debug.Log("Task finished execution"); 
});

This package also offers to useful features extra to manage lists or pools of threads: Task.WhenAll: Creates a task that waits for all the thread to finish (for example waits to receive a confirmation from all the connected clients)

// this task will wait for all task to finish 
Task.WhenAll (tasks).ContinueInMainThreadWith (DoSomethingWithTheResult);

Task.WhenAny: Creates a task that waits for the execution of one thread in the pool (for example if the game needs to get some data from the internet, and this data is available in multiple server, and it doesn’t matter from where it comes, as long as the data is obtained from one server the game doesn’t need to wait for the other servers to reply)

Task.WhenAny (tasks).ContinueInMainThreadWith ((t) => 
{ 
   t.AbortThread(); // to cancel the remaining threads     
   DoSomethingWithTheResult(t); 
});

A more complicated, real life example: get the full contents of a paginated leaderboard from a server… but we don’t want to wait to have the full board ready, we want to show the result as we get them:

bool m_stopProcessing; 
Task GetCompleteLeaderboard(Action<int, string> intermediateResult) 
{ 
   TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool> ();    
   GetCompleteLeaderboardAux (0, tcs, intermediateResult); 
   return tcs.Task; 
} 

void GetCompleteLeaderboardAux(int offset, TaskCompletionSource<bool> tcs, Action<int, string> intermediateResult) 
{ 
   if (m_stopProcessing) 
   { 
      m_stopProcessing= false; 
      tcs.SetError(new Exception("User cancelled")); 
   } 
   else 
   { 
      StartCoroutine(ConnectToAPI(offset, tcs, intermediateResult)); 
   } 
} 

const int queryLimit= 10; 
IEnumerator ConnectToAPI(int offset, TaskCompletionSource<bool> tcs, Action<int, string> intermediateResult) 
{ 
   yield return StartCoroutine(YOUR_FAVORITE_API_GetLeaderBoardUsingWWW (offset, queryLimit)); 
   SortedList<int, string> result = YOUR_FAVORITE_API_GetResultsFromCall (); 
   if(result== null) 
   { // mockup an error in the API 
      tcs.SetError(new Exception("API returns NULL")); 
   } 
   foreach(int k in result.Keys) 
   { 
      intermediateResult(k, result[k]); 
   } 
   if (result.Count == queryLimit) 
   { 
      GetCompleteLeaderboardAux(offset + queryLimit, tcs, intermediateResult); 
   } 
   else 
   {
     tcs.SetResult(true); 
   } 
}

This package reimplements and extends the .NET System.Threading.Tasks namespace. This namespace makes thread management easier for you by adding a class named Task.

A task represents an asynchronous operation. Typically, a Task is returned from an asynchronous function and gives the ability to continue processing the result of the task.

A task is not tied to a particular threading model: it represents the work being done, not where it is executing. Tasks have many advantages over other methods of asynchronous programming such as callbacks and the event model.

You can learn more about tasks in Parse’s website Tested for standalone builds, web player, iOS and Android Full source code is included, as well as many examples. I use this asset for my own projects, so I will keep improving and expanding it. If you have any comment, doubt, feature request or just need some help implementing some multithreading behaviour just let me know in the forum’s thread