mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-10 04:49:28 -05:00
Move DepthFirstScheduler to Assets/*
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public class DepthFirstScheduler
|
||||
{
|
||||
[Test]
|
||||
public void ScheduleTreeTest()
|
||||
{
|
||||
var s = Schedulable.Create();
|
||||
|
||||
var tasks = s.GetRoot().Traverse().ToArray();
|
||||
Assert.AreEqual(2, tasks.Length);
|
||||
|
||||
var task_int = s.AddTask(Scheduler.CurrentThread, () => 0);
|
||||
task_int = task_int.ContinueWith(Scheduler.CurrentThread, _ => 1);
|
||||
|
||||
var status = s.Execute();
|
||||
Assert.AreEqual(ExecutionStatus.Done, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public class DepthFirstScheduler
|
||||
{
|
||||
[Test]
|
||||
public void ScheduleTreeTest()
|
||||
{
|
||||
var s = Schedulable.Create();
|
||||
|
||||
var tasks = s.GetRoot().Traverse().ToArray();
|
||||
Assert.AreEqual(2, tasks.Length);
|
||||
|
||||
var task_int = s.AddTask(Scheduler.CurrentThread, () => 0);
|
||||
task_int = task_int.ContinueWith(Scheduler.CurrentThread, _ => 1);
|
||||
|
||||
var status = s.Execute();
|
||||
Assert.AreEqual(ExecutionStatus.Done, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,192 +1,192 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ExecutionStatus
|
||||
{
|
||||
Unknown,
|
||||
Done,
|
||||
Continue, // coroutine or schedulable
|
||||
Error,
|
||||
}
|
||||
|
||||
public interface IFunctor<T>
|
||||
{
|
||||
T GetResult();
|
||||
Exception GetError();
|
||||
ExecutionStatus Execute();
|
||||
}
|
||||
|
||||
#region Functor
|
||||
public class Functor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Action m_pred;
|
||||
public Functor(Func<T> func)
|
||||
{
|
||||
m_pred = () => m_result = func();
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_pred();
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Functor
|
||||
{
|
||||
/// <summary>
|
||||
/// 引数の型を隠蔽した実行器を生成する
|
||||
/// </summary>
|
||||
/// <typeparam name="S">引数の型</typeparam>
|
||||
/// <typeparam name="T">結果の型</typeparam>
|
||||
/// <param name="arg"></param>
|
||||
/// <param name="pred"></param>
|
||||
/// <returns></returns>
|
||||
public static Functor<T> Create<S, T>(Func<S> arg, Func<S, T> pred)
|
||||
{
|
||||
return new Functor<T>(() => pred(arg()));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CoroutineFunctor
|
||||
public class CoroutineFunctor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Func<T> m_arg;
|
||||
Func<T, IEnumerator> m_starter;
|
||||
Stack<IEnumerator> m_it;
|
||||
public CoroutineFunctor(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
m_arg = arg;
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_it == null)
|
||||
{
|
||||
m_result = m_arg();
|
||||
m_it = new Stack<IEnumerator>();
|
||||
m_it.Push(m_starter(m_result));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (m_it.Count!=0)
|
||||
{
|
||||
if (m_it.Peek().MoveNext())
|
||||
{
|
||||
var nested = m_it.Peek().Current as IEnumerator;
|
||||
if (nested!=null)
|
||||
{
|
||||
m_it.Push(nested);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_it.Pop();
|
||||
}
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoroutineFunctor
|
||||
{
|
||||
public static CoroutineFunctor<T> Create<T>(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
return new CoroutineFunctor<T>(arg, starter);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public class SchedulableFunctor<T> : IFunctor<T>
|
||||
{
|
||||
Schedulable<T> m_schedulable;
|
||||
Func<Schedulable<T>> m_starter;
|
||||
TaskChain m_chain;
|
||||
|
||||
public SchedulableFunctor(Func<Schedulable<T>> starter)
|
||||
{
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_chain == null)
|
||||
{
|
||||
m_schedulable = m_starter();
|
||||
m_chain = TaskChain.Schedule(m_schedulable, ex => m_error = ex);
|
||||
}
|
||||
|
||||
return m_chain.Next();
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
return m_schedulable.Func.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableFunctor
|
||||
{
|
||||
public static SchedulableFunctor<T> Create<T>(Func<Schedulable<T>> starter)
|
||||
{
|
||||
return new SchedulableFunctor<T>(starter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ExecutionStatus
|
||||
{
|
||||
Unknown,
|
||||
Done,
|
||||
Continue, // coroutine or schedulable
|
||||
Error,
|
||||
}
|
||||
|
||||
public interface IFunctor<T>
|
||||
{
|
||||
T GetResult();
|
||||
Exception GetError();
|
||||
ExecutionStatus Execute();
|
||||
}
|
||||
|
||||
#region Functor
|
||||
public class Functor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Action m_pred;
|
||||
public Functor(Func<T> func)
|
||||
{
|
||||
m_pred = () => m_result = func();
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_pred();
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Functor
|
||||
{
|
||||
/// <summary>
|
||||
/// 引数の型を隠蔽した実行器を生成する
|
||||
/// </summary>
|
||||
/// <typeparam name="S">引数の型</typeparam>
|
||||
/// <typeparam name="T">結果の型</typeparam>
|
||||
/// <param name="arg"></param>
|
||||
/// <param name="pred"></param>
|
||||
/// <returns></returns>
|
||||
public static Functor<T> Create<S, T>(Func<S> arg, Func<S, T> pred)
|
||||
{
|
||||
return new Functor<T>(() => pred(arg()));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CoroutineFunctor
|
||||
public class CoroutineFunctor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Func<T> m_arg;
|
||||
Func<T, IEnumerator> m_starter;
|
||||
Stack<IEnumerator> m_it;
|
||||
public CoroutineFunctor(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
m_arg = arg;
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_it == null)
|
||||
{
|
||||
m_result = m_arg();
|
||||
m_it = new Stack<IEnumerator>();
|
||||
m_it.Push(m_starter(m_result));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (m_it.Count!=0)
|
||||
{
|
||||
if (m_it.Peek().MoveNext())
|
||||
{
|
||||
var nested = m_it.Peek().Current as IEnumerator;
|
||||
if (nested!=null)
|
||||
{
|
||||
m_it.Push(nested);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_it.Pop();
|
||||
}
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoroutineFunctor
|
||||
{
|
||||
public static CoroutineFunctor<T> Create<T>(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
return new CoroutineFunctor<T>(arg, starter);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public class SchedulableFunctor<T> : IFunctor<T>
|
||||
{
|
||||
Schedulable<T> m_schedulable;
|
||||
Func<Schedulable<T>> m_starter;
|
||||
TaskChain m_chain;
|
||||
|
||||
public SchedulableFunctor(Func<Schedulable<T>> starter)
|
||||
{
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_chain == null)
|
||||
{
|
||||
m_schedulable = m_starter();
|
||||
m_chain = TaskChain.Schedule(m_schedulable, ex => m_error = ex);
|
||||
}
|
||||
|
||||
return m_chain.Next();
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
return m_schedulable.Func.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableFunctor
|
||||
{
|
||||
public static SchedulableFunctor<T> Create<T>(Func<Schedulable<T>> starter)
|
||||
{
|
||||
return new SchedulableFunctor<T>(starter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace
|
||||
DepthFirstScheduler
|
||||
{
|
||||
public static class IEnumeratorExtensions
|
||||
{
|
||||
public static void CoroutinetoEnd(this IEnumerator coroutine)
|
||||
{
|
||||
var stack = new Stack<IEnumerator>();
|
||||
stack.Push(coroutine);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
if (stack.Peek().MoveNext())
|
||||
{
|
||||
var nested = stack.Peek().Current as IEnumerator;
|
||||
if (nested != null)
|
||||
{
|
||||
stack.Push(nested);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace
|
||||
DepthFirstScheduler
|
||||
{
|
||||
public static class IEnumeratorExtensions
|
||||
{
|
||||
public static void CoroutinetoEnd(this IEnumerator coroutine)
|
||||
{
|
||||
var stack = new Stack<IEnumerator>();
|
||||
stack.Push(coroutine);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
if (stack.Peek().MoveNext())
|
||||
{
|
||||
var nested = stack.Peek().Current as IEnumerator;
|
||||
if (nested != null)
|
||||
{
|
||||
stack.Push(nested);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +1,95 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public class LockQueue<T> where T : class
|
||||
{
|
||||
List<T> m_queue = new List<T>();
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
return m_queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
m_queue.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue(out int remain)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0)
|
||||
{
|
||||
remain = 0;
|
||||
return null;
|
||||
}
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
remain = m_queue.Count;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0) return null;
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LockQueueForValue<T> where T : struct
|
||||
{
|
||||
List<T> m_queue = new List<T>();
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
return m_queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
m_queue.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryDequeue(out T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0)
|
||||
{
|
||||
t = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
t = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public class LockQueue<T> where T : class
|
||||
{
|
||||
List<T> m_queue = new List<T>();
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
return m_queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
m_queue.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue(out int remain)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0)
|
||||
{
|
||||
remain = 0;
|
||||
return null;
|
||||
}
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
remain = m_queue.Count;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0) return null;
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LockQueueForValue<T> where T : struct
|
||||
{
|
||||
List<T> m_queue = new List<T>();
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
return m_queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
m_queue.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryDequeue(out T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0)
|
||||
{
|
||||
t = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
t = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,150 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// UniRxのMainThreadDispatcherを参考にした。
|
||||
/// * https://github.com/neuecc/UniRx/blob/master/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs
|
||||
/// </summary>
|
||||
public class MainThreadDispatcher : MonoBehaviour
|
||||
{
|
||||
|
||||
[Header("Debug")]
|
||||
public int TaskCount;
|
||||
|
||||
IEnumerable<Transform> Ancestors(Transform t)
|
||||
{
|
||||
yield return t;
|
||||
|
||||
if (t.parent != null)
|
||||
{
|
||||
foreach (var x in Ancestors(t.parent))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TaskCount = Scheduler.MainThread.UpdateAndGetTaskCount();
|
||||
}
|
||||
|
||||
static MainThreadDispatcher instance;
|
||||
static bool initialized;
|
||||
static bool isQuitting = false;
|
||||
|
||||
public static bool IsInitialized
|
||||
{
|
||||
get { return initialized && instance != null; }
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
static object mainThreadToken;
|
||||
|
||||
public static MainThreadDispatcher Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
Initialize();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
MainThreadDispatcher dispatcher = null;
|
||||
|
||||
try
|
||||
{
|
||||
dispatcher = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Throw exception when calling from a worker thread.
|
||||
var ex = new Exception(
|
||||
"DepthFirstScheduler requires a MainThreadDispatcher component created on the main thread."
|
||||
+ " Make sure it is added to the scene before calling DepthFirstScheduler from a worker thread.");
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (isQuitting)
|
||||
{
|
||||
// don't create new instance after quitting
|
||||
// avoid "Some objects were not cleaned up when closing the scene find target" error.
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatcher == null)
|
||||
{
|
||||
// awake call immediately from UnityEngine
|
||||
new GameObject("DepthFirstScheduler").AddComponent<MainThreadDispatcher>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.Awake(); // force awake
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsInMainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
return (mainThreadToken != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
Debug.Log("Initialize UniTask.MainThredDispatcher");
|
||||
|
||||
instance = this;
|
||||
mainThreadToken = new object();
|
||||
initialized = true;
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this != instance)
|
||||
{
|
||||
Debug.LogWarning("There is already a MainThreadDispatcher in the scene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (instance == this)
|
||||
{
|
||||
instance = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
initialized = instance != null;
|
||||
}
|
||||
|
||||
if (Scheduler.SingleWorkerThread != null)
|
||||
{
|
||||
Scheduler.SingleWorkerThread.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
isQuitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// UniRxのMainThreadDispatcherを参考にした。
|
||||
/// * https://github.com/neuecc/UniRx/blob/master/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs
|
||||
/// </summary>
|
||||
public class MainThreadDispatcher : MonoBehaviour
|
||||
{
|
||||
|
||||
[Header("Debug")]
|
||||
public int TaskCount;
|
||||
|
||||
IEnumerable<Transform> Ancestors(Transform t)
|
||||
{
|
||||
yield return t;
|
||||
|
||||
if (t.parent != null)
|
||||
{
|
||||
foreach (var x in Ancestors(t.parent))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TaskCount = Scheduler.MainThread.UpdateAndGetTaskCount();
|
||||
}
|
||||
|
||||
static MainThreadDispatcher instance;
|
||||
static bool initialized;
|
||||
static bool isQuitting = false;
|
||||
|
||||
public static bool IsInitialized
|
||||
{
|
||||
get { return initialized && instance != null; }
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
static object mainThreadToken;
|
||||
|
||||
public static MainThreadDispatcher Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
Initialize();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
MainThreadDispatcher dispatcher = null;
|
||||
|
||||
try
|
||||
{
|
||||
dispatcher = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Throw exception when calling from a worker thread.
|
||||
var ex = new Exception(
|
||||
"DepthFirstScheduler requires a MainThreadDispatcher component created on the main thread."
|
||||
+ " Make sure it is added to the scene before calling DepthFirstScheduler from a worker thread.");
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (isQuitting)
|
||||
{
|
||||
// don't create new instance after quitting
|
||||
// avoid "Some objects were not cleaned up when closing the scene find target" error.
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatcher == null)
|
||||
{
|
||||
// awake call immediately from UnityEngine
|
||||
new GameObject("DepthFirstScheduler").AddComponent<MainThreadDispatcher>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.Awake(); // force awake
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsInMainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
return (mainThreadToken != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
Debug.Log("Initialize UniTask.MainThredDispatcher");
|
||||
|
||||
instance = this;
|
||||
mainThreadToken = new object();
|
||||
initialized = true;
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this != instance)
|
||||
{
|
||||
Debug.LogWarning("There is already a MainThreadDispatcher in the scene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (instance == this)
|
||||
{
|
||||
instance = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
initialized = instance != null;
|
||||
}
|
||||
|
||||
if (Scheduler.SingleWorkerThread != null)
|
||||
{
|
||||
Scheduler.SingleWorkerThread.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
isQuitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx
|
||||
///
|
||||
/// 終了を通知するにはnullを投入する手が使える
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class MonitorQueue<T>
|
||||
{
|
||||
private Int32 _count = 0;
|
||||
public Int32 Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<T> _queue = new Queue<T>();
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
while (_count <= 0) Monitor.Wait(_queue);
|
||||
_count--;
|
||||
return _queue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T data)
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
_queue.Enqueue(data);
|
||||
_count++;
|
||||
Monitor.Pulse(_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx
|
||||
///
|
||||
/// 終了を通知するにはnullを投入する手が使える
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class MonitorQueue<T>
|
||||
{
|
||||
private Int32 _count = 0;
|
||||
public Int32 Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<T> _queue = new Queue<T>();
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
while (_count <= 0) Monitor.Wait(_queue);
|
||||
_count--;
|
||||
return _queue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T data)
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
_queue.Enqueue(data);
|
||||
_count++;
|
||||
Monitor.Pulse(_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,241 +1,241 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if ((NET_4_6 || NET_STANDARD_2_0) && UNITY_2017_1_OR_NEWER)
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface ISchedulable
|
||||
{
|
||||
/// <returns>実行が終了したか?Coroutineの実行が一回で終わらない場合がある</returns>
|
||||
ExecutionStatus Execute();
|
||||
Exception GetError();
|
||||
IScheduler Schedulder { get; }
|
||||
|
||||
ISchedulable Parent { get; set; }
|
||||
void AddChild(ISchedulable child);
|
||||
IEnumerable<ISchedulable> Traverse();
|
||||
}
|
||||
|
||||
public static class ISchedulableExtensions
|
||||
{
|
||||
public static ISchedulable GetRoot(this ISchedulable self)
|
||||
{
|
||||
var current = self;
|
||||
while (current.Parent != null)
|
||||
{
|
||||
current = current.Parent;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
public class NoParentException: Exception
|
||||
{
|
||||
public NoParentException():base("No parent task can't ContinueWith or OnExecute. First AddTask")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class Schedulable<T> : ISchedulable
|
||||
{
|
||||
List<ISchedulable> m_children = new List<ISchedulable>();
|
||||
public void AddChild(ISchedulable child)
|
||||
{
|
||||
child.Parent = this;
|
||||
m_children.Add(child);
|
||||
}
|
||||
public IEnumerable<ISchedulable> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in m_children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ISchedulable Parent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IScheduler Schedulder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IFunctor<T> Func
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Exception GetError()
|
||||
{
|
||||
return Func.GetError();
|
||||
}
|
||||
|
||||
public Schedulable()
|
||||
{
|
||||
}
|
||||
|
||||
public Schedulable(IScheduler scheduler, IFunctor<T> func)
|
||||
{
|
||||
Schedulder = scheduler;
|
||||
Func = func;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (Func == null)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
return Func.Execute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// スケジュールされたタスクをすべて即時に実行する
|
||||
/// </summary>
|
||||
public void ExecuteAll()
|
||||
{
|
||||
foreach (var x in this.GetRoot().Traverse())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var status = x.Execute();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
if (status == ExecutionStatus.Error)
|
||||
{
|
||||
throw x.GetError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Coroutineタスクが継続している
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Schedulable<Unit> AddTask(IScheduler scheduler, Action pred)
|
||||
{
|
||||
return AddTask(scheduler, () => { pred(); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> AddTask<U>(IScheduler scheduler, Func<U> pred)
|
||||
{
|
||||
var schedulable = new Schedulable<U>(scheduler, Functor.Create(() => Unit.Default, _ => pred()));
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> AddCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> ContinueWith(IScheduler scheduler, Action<T> pred)
|
||||
{
|
||||
return ContinueWith(scheduler, t => { pred(t); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> ContinueWith<U>(IScheduler scheduler, Func<T, U> pred)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
var func = Functor.Create(getResult, pred);
|
||||
var schedulable = new Schedulable<U>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> ContinueWithCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> OnExecute(IScheduler scheduler, Action<Schedulable<Unit>> pred)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
|
||||
var schedulable = new Schedulable<Unit>();
|
||||
schedulable.Func = Functor.Create(getResult, _ => { pred(schedulable); return Unit.Default; });
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Schedulable
|
||||
{
|
||||
public static Schedulable<Unit> Create()
|
||||
{
|
||||
return new Schedulable<Unit>().AddTask(Scheduler.CurrentThread, () =>
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableExtensions
|
||||
{
|
||||
public static void Subscribe<T>(
|
||||
this Schedulable<T> schedulable,
|
||||
IScheduler scheduler,
|
||||
Action<T> onCompleted,
|
||||
Action<Exception> onError)
|
||||
{
|
||||
schedulable.ContinueWith(scheduler, onCompleted);
|
||||
TaskChain.Schedule(schedulable.GetRoot(), onError);
|
||||
}
|
||||
|
||||
#if ((NET_4_6 || NET_STANDARD_2_0) && UNITY_2017_1_OR_NEWER)
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable)
|
||||
{
|
||||
return ToTask(schedulable, Scheduler.MainThread);
|
||||
}
|
||||
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable, IScheduler scheduler)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
schedulable.Subscribe(scheduler, r => tcs.TrySetResult(r), ex => tcs.TrySetException(ex));
|
||||
return tcs.Task;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if ((NET_4_6 || NET_STANDARD_2_0) && UNITY_2017_1_OR_NEWER)
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface ISchedulable
|
||||
{
|
||||
/// <returns>実行が終了したか?Coroutineの実行が一回で終わらない場合がある</returns>
|
||||
ExecutionStatus Execute();
|
||||
Exception GetError();
|
||||
IScheduler Schedulder { get; }
|
||||
|
||||
ISchedulable Parent { get; set; }
|
||||
void AddChild(ISchedulable child);
|
||||
IEnumerable<ISchedulable> Traverse();
|
||||
}
|
||||
|
||||
public static class ISchedulableExtensions
|
||||
{
|
||||
public static ISchedulable GetRoot(this ISchedulable self)
|
||||
{
|
||||
var current = self;
|
||||
while (current.Parent != null)
|
||||
{
|
||||
current = current.Parent;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
public class NoParentException: Exception
|
||||
{
|
||||
public NoParentException():base("No parent task can't ContinueWith or OnExecute. First AddTask")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class Schedulable<T> : ISchedulable
|
||||
{
|
||||
List<ISchedulable> m_children = new List<ISchedulable>();
|
||||
public void AddChild(ISchedulable child)
|
||||
{
|
||||
child.Parent = this;
|
||||
m_children.Add(child);
|
||||
}
|
||||
public IEnumerable<ISchedulable> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in m_children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ISchedulable Parent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IScheduler Schedulder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IFunctor<T> Func
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Exception GetError()
|
||||
{
|
||||
return Func.GetError();
|
||||
}
|
||||
|
||||
public Schedulable()
|
||||
{
|
||||
}
|
||||
|
||||
public Schedulable(IScheduler scheduler, IFunctor<T> func)
|
||||
{
|
||||
Schedulder = scheduler;
|
||||
Func = func;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (Func == null)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
return Func.Execute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// スケジュールされたタスクをすべて即時に実行する
|
||||
/// </summary>
|
||||
public void ExecuteAll()
|
||||
{
|
||||
foreach (var x in this.GetRoot().Traverse())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var status = x.Execute();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
if (status == ExecutionStatus.Error)
|
||||
{
|
||||
throw x.GetError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Coroutineタスクが継続している
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Schedulable<Unit> AddTask(IScheduler scheduler, Action pred)
|
||||
{
|
||||
return AddTask(scheduler, () => { pred(); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> AddTask<U>(IScheduler scheduler, Func<U> pred)
|
||||
{
|
||||
var schedulable = new Schedulable<U>(scheduler, Functor.Create(() => Unit.Default, _ => pred()));
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> AddCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> ContinueWith(IScheduler scheduler, Action<T> pred)
|
||||
{
|
||||
return ContinueWith(scheduler, t => { pred(t); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> ContinueWith<U>(IScheduler scheduler, Func<T, U> pred)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
var func = Functor.Create(getResult, pred);
|
||||
var schedulable = new Schedulable<U>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> ContinueWithCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> OnExecute(IScheduler scheduler, Action<Schedulable<Unit>> pred)
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
throw new NoParentException();
|
||||
}
|
||||
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
|
||||
var schedulable = new Schedulable<Unit>();
|
||||
schedulable.Func = Functor.Create(getResult, _ => { pred(schedulable); return Unit.Default; });
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Schedulable
|
||||
{
|
||||
public static Schedulable<Unit> Create()
|
||||
{
|
||||
return new Schedulable<Unit>().AddTask(Scheduler.CurrentThread, () =>
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableExtensions
|
||||
{
|
||||
public static void Subscribe<T>(
|
||||
this Schedulable<T> schedulable,
|
||||
IScheduler scheduler,
|
||||
Action<T> onCompleted,
|
||||
Action<Exception> onError)
|
||||
{
|
||||
schedulable.ContinueWith(scheduler, onCompleted);
|
||||
TaskChain.Schedule(schedulable.GetRoot(), onError);
|
||||
}
|
||||
|
||||
#if ((NET_4_6 || NET_STANDARD_2_0) && UNITY_2017_1_OR_NEWER)
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable)
|
||||
{
|
||||
return ToTask(schedulable, Scheduler.MainThread);
|
||||
}
|
||||
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable, IScheduler scheduler)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
schedulable.Subscribe(scheduler, r => tcs.TrySetResult(r), ex => tcs.TrySetException(ex));
|
||||
return tcs.Task;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface IScheduler : IDisposable
|
||||
{
|
||||
void Enqueue(TaskChain item);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface IScheduler : IDisposable
|
||||
{
|
||||
void Enqueue(TaskChain item);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,91 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ChainStatus
|
||||
{
|
||||
Unknown,
|
||||
Continue,
|
||||
Done,
|
||||
Error,
|
||||
}
|
||||
|
||||
public class TaskChain
|
||||
{
|
||||
public IEnumerator<ISchedulable> Enumerator;
|
||||
public Action<Exception> OnError;
|
||||
public ChainStatus ChainStatus;
|
||||
|
||||
public static TaskChain Schedule(ISchedulable schedulable, Action<Exception> onError)
|
||||
{
|
||||
var item = new TaskChain
|
||||
{
|
||||
Enumerator = schedulable.Traverse().GetEnumerator(),
|
||||
OnError = onError
|
||||
};
|
||||
|
||||
if (item.Enumerator.MoveNext())
|
||||
{
|
||||
if (item.Enumerator.Current.Schedulder == null)
|
||||
{
|
||||
// default
|
||||
Scheduler.MainThread.Enqueue(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Enumerator.Current.Schedulder.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ExecutionStatus Next()
|
||||
{
|
||||
if (this.ChainStatus == ChainStatus.Done
|
||||
|| this.ChainStatus== ChainStatus.Error)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
{
|
||||
var status = Enumerator.Current.Execute();
|
||||
if (status == ExecutionStatus.Error)
|
||||
{
|
||||
ChainStatus = ChainStatus.Error;
|
||||
OnError(Enumerator.Current.GetError());
|
||||
}
|
||||
if (status == ExecutionStatus.Continue)
|
||||
{
|
||||
// 中断(coroutine)
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enumerator.MoveNext())
|
||||
{
|
||||
// 終了
|
||||
ChainStatus = ChainStatus.Done;
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
if (Enumerator.Current.Schedulder != null)
|
||||
{
|
||||
// Scheduleして中断
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
Enumerator.Current.Schedulder.Enqueue(this);
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
return Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ChainStatus
|
||||
{
|
||||
Unknown,
|
||||
Continue,
|
||||
Done,
|
||||
Error,
|
||||
}
|
||||
|
||||
public class TaskChain
|
||||
{
|
||||
public IEnumerator<ISchedulable> Enumerator;
|
||||
public Action<Exception> OnError;
|
||||
public ChainStatus ChainStatus;
|
||||
|
||||
public static TaskChain Schedule(ISchedulable schedulable, Action<Exception> onError)
|
||||
{
|
||||
var item = new TaskChain
|
||||
{
|
||||
Enumerator = schedulable.Traverse().GetEnumerator(),
|
||||
OnError = onError
|
||||
};
|
||||
|
||||
if (item.Enumerator.MoveNext())
|
||||
{
|
||||
if (item.Enumerator.Current.Schedulder == null)
|
||||
{
|
||||
// default
|
||||
Scheduler.MainThread.Enqueue(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Enumerator.Current.Schedulder.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ExecutionStatus Next()
|
||||
{
|
||||
if (this.ChainStatus == ChainStatus.Done
|
||||
|| this.ChainStatus== ChainStatus.Error)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
{
|
||||
var status = Enumerator.Current.Execute();
|
||||
if (status == ExecutionStatus.Error)
|
||||
{
|
||||
ChainStatus = ChainStatus.Error;
|
||||
OnError(Enumerator.Current.GetError());
|
||||
}
|
||||
if (status == ExecutionStatus.Continue)
|
||||
{
|
||||
// 中断(coroutine)
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enumerator.MoveNext())
|
||||
{
|
||||
// 終了
|
||||
ChainStatus = ChainStatus.Done;
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
if (Enumerator.Current.Schedulder != null)
|
||||
{
|
||||
// Scheduleして中断
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
Enumerator.Current.Schedulder.Enqueue(this);
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
return Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
[Serializable]
|
||||
public struct Unit : IEquatable<Unit>
|
||||
{
|
||||
static readonly Unit @default = new Unit();
|
||||
|
||||
public static Unit Default { get { return @default; } }
|
||||
|
||||
public static bool operator ==(Unit first, Unit second)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(Unit first, Unit second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Unit other)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Unit;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
[Serializable]
|
||||
public struct Unit : IEquatable<Unit>
|
||||
{
|
||||
static readonly Unit @default = new Unit();
|
||||
|
||||
public static Unit Default { get { return @default; } }
|
||||
|
||||
public static bool operator ==(Unit first, Unit second)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(Unit first, Unit second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Unit other)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Unit;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user