Last active
September 23, 2019 12:57
-
-
Save TobiasPott/6f5945313d9798e30ad4512fd24e0ec7 to your computer and use it in GitHub Desktop.
Helper class to execute Unity3D Coroutines without an explicit MonoBehaviour reference
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
#if NET_4_6 || NET_STANDARD_2_0 | |
using System.Threading.Tasks; | |
#endif | |
using UnityEngine; | |
public class Coroutiner : MonoBehaviour | |
{ | |
private static Coroutiner _instance = null; | |
public static Coroutiner Instance | |
{ | |
get | |
{ | |
if (_instance == null) | |
{ | |
GameObject goInst = new GameObject("Coroutiner", typeof(Coroutiner)); | |
_instance = goInst.GetComponent<Coroutiner>(); | |
GameObject.DontDestroyOnLoad(goInst); | |
} | |
return _instance; | |
} | |
} | |
private void Awake() | |
{ | |
if (_instance == null || _instance == this) | |
_instance = this; | |
else | |
GameObject.Destroy(this.gameObject); | |
GameObject.DontDestroyOnLoad(this.gameObject); | |
} | |
public static Coroutine Start(IEnumerator routine) | |
{ return Coroutiner.Instance.StartCoroutine(routine); } | |
public static void Stop(IEnumerator routine) | |
{ Coroutiner.Instance.StopCoroutine(routine); } | |
public static void Stop(Coroutine routine) | |
{ Coroutiner.Instance.StopCoroutine(routine); } | |
public static void StopAll() | |
{ Coroutiner.Instance.StopAllCoroutines(); } | |
/* | |
public class ThreadParameters | |
{ | |
public const string PN_Mutex = "_internal_Mutex"; | |
private Mutex _mutex = null; | |
private Dictionary<string, object> _params = new Dictionary<string, object>(); | |
public Mutex Mutex | |
{ get { return _mutex; } } | |
public object this[string key] | |
{ get { return _params[key]; } } | |
public ThreadParameters() | |
{ | |
_mutex = new Mutex(); | |
_params.Add(PN_Mutex, _mutex); | |
} | |
public void AddParameter(string name, object value) | |
{ if (!_params.ContainsKey(name)) _params.Add(name, value); } | |
public void RemoveParameter(string name) | |
{ if (_params.ContainsKey(name)) _params.Remove(name); } | |
} | |
public static void StartAsThread(Action<object> target, ThreadParameters parameters) | |
{ | |
ThreadPool.QueueUserWorkItem(new WaitCallback(target), parameters); | |
//return mutex; | |
} | |
*/ | |
// ======================== | |
// paste this into a active behaviour to test threaded processing of stuff | |
// ======================== | |
//private void Update() | |
//{ | |
// if (Input.GetKeyDown(KeyCode.T)) | |
// { | |
// this.StartCoroutine(Coroutiner.COR_StartThread(Coroutiner.UseResource)); | |
// } | |
//} | |
/* | |
public static IEnumerator COR_StartThread(Action<object> task) | |
{ | |
Coroutiner.WaitCallbackParameters threadParams = new Coroutiner.WaitCallbackParameters(); | |
System.Threading.Mutex mutex = threadParams.Mutex; | |
Coroutiner.StartAsThread(task, threadParams); | |
Debug.Log("Thread started: " + Time.time); | |
System.Threading.WaitHandle[] waitHandles = new System.Threading.WaitHandle[] { mutex }; | |
do { yield return null; } | |
while (!System.Threading.Mutex.WaitAll(waitHandles, 33)); | |
Debug.Log("Thread ended: " + Time.time); | |
} | |
public static Vector3 _result = Vector3.zero; | |
// This method represents a resource that must be synchronized | |
// so that only one thread at a time can enter. | |
public static void UseResource(object objectInfo) | |
{ | |
Coroutiner.WaitCallbackParameters parameters = (Coroutiner.WaitCallbackParameters)objectInfo; | |
System.Threading.Mutex mutex = parameters.Mutex; | |
mutex.WaitOne(); | |
// Wait until it is safe to enter. | |
Debug.Log("{0} is requesting the mutex"); | |
Debug.Log("{0} has entered the protected area"); | |
// Place code to access non-reentrant resources here. | |
// Simulate some work. | |
//System.Threading.Thread.Sleep(500); | |
System.Random rnd = new System.Random(); | |
for (int i = 0; i < 10000000; i++) | |
{ | |
_result += Vector3.up * (float)(rnd.NextDouble() * 2 - 2); | |
} | |
Debug.Log("{0} is leaving the protected area"); | |
// Release the Mutex. | |
mutex.ReleaseMutex(); | |
Debug.Log("{0} has released the mutex: " + _result.ToString("0.000")); | |
} | |
*/ | |
} | |
#if NET_4_6 || NET_STANDARD_2_0 | |
public class TaskResult | |
{ | |
public System.Threading.Tasks.TaskStatus Status { get; set; } = System.Threading.Tasks.TaskStatus.Created; | |
} | |
public class TaskResult<T> : TaskResult | |
{ | |
public T Value { get; set; } | |
} | |
public static class CoroutinerExtensions | |
{ | |
/// <summary> | |
/// converts a <c>System.Threading.Tasks.Task<T></c> to be run as a Unity coroutine | |
/// </summary> | |
/// <typeparam name="T">The type to return from the task process</typeparam> | |
/// <param name="task">The task instance to convert into a coroutine</param> | |
/// <param name="result">A <c>TaskResult<T></c> which stores the tasks result and final status.</param> | |
/// <returns>An enumerator to be used as a coroutine in Unity</returns> | |
public static IEnumerator ToCoroutine<T>(this System.Threading.Tasks.Task<T> task, TaskResult<T> result) | |
{ | |
yield return null; | |
do | |
{ yield return null; } | |
while (!HasTaskFinished(task) && !task.IsFaulted && !task.IsCanceled); | |
result.Status = task.Status; | |
if (result.Status == System.Threading.Tasks.TaskStatus.RanToCompletion) | |
result.Value = task.Result; | |
} | |
/// <summary> | |
/// converts a <c>System.Threading.Tasks.Task</c> to be run as a Unity coroutine | |
/// </summary> | |
/// <param name="task">The task instance to convert into a coroutine</param> | |
/// <param name="result">A <c>TaskResult</c> which stores the tasks result and final status.</param> | |
/// <returns></returns> | |
public static IEnumerator ToCoroutine(this Task task, TaskResult result) | |
{ | |
yield return null; | |
do | |
{ yield return null; } | |
while (!HasTaskFinished(task)); | |
result.Status = task.Status; | |
} | |
private static bool HasTaskFinished(System.Threading.Tasks.Task task) | |
{ | |
switch (task.Status) | |
{ | |
// check for the task status to determine it has finished (either errored, cancelled or completed) | |
case System.Threading.Tasks.TaskStatus.Canceled: | |
case System.Threading.Tasks.TaskStatus.Faulted: | |
case System.Threading.Tasks.TaskStatus.RanToCompletion: | |
return true; | |
} | |
return false; | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment