mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-14 14:29:52 -05:00
Merge commit 'f20f27259c28dbff6697958b8727d39d24f74ce1' as 'DepthFirstScheduler'
Co-authored-by: ousttrue <ousttrue@gmail.com> Co-authored-by: TORISOUP <tori.birdstrike@gmail.com> Co-authored-by: yutopp <yutopp@gmail.com>
This commit is contained in:
commit
d43d135c80
9
DepthFirstScheduler/Editor.meta
Normal file
9
DepthFirstScheduler/Editor.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc0ab91a2011fcf4d925dd94bccdb243
|
||||
folderAsset: yes
|
||||
timeCreated: 1540294739
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
24
DepthFirstScheduler/Editor/DepthFirstScheduler.cs
Normal file
24
DepthFirstScheduler/Editor/DepthFirstScheduler.cs
Normal file
|
|
@ -0,0 +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);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Editor/DepthFirstScheduler.cs.meta
Normal file
12
DepthFirstScheduler/Editor/DepthFirstScheduler.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3003e87b5df13394eadfda925bb816e5
|
||||
timeCreated: 1540294752
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
192
DepthFirstScheduler/Functor.cs
Normal file
192
DepthFirstScheduler/Functor.cs
Normal file
|
|
@ -0,0 +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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
12
DepthFirstScheduler/Functor.cs.meta
Normal file
12
DepthFirstScheduler/Functor.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c320f3f577dde634a871dc88266c2a20
|
||||
timeCreated: 1520084196
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
DepthFirstScheduler/IEnumeratorExtensions.cs
Normal file
31
DepthFirstScheduler/IEnumeratorExtensions.cs
Normal file
|
|
@ -0,0 +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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
DepthFirstScheduler/IEnumeratorExtensions.cs.meta
Normal file
11
DepthFirstScheduler/IEnumeratorExtensions.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4719fc9e6319c654b8a4818bef2c3a85
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
DepthFirstScheduler/LICENSE
Normal file
21
DepthFirstScheduler/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 ousttrue
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
8
DepthFirstScheduler/LICENSE.meta
Normal file
8
DepthFirstScheduler/LICENSE.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b673d33707cbc5446870804437f3cbea
|
||||
timeCreated: 1535290899
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
95
DepthFirstScheduler/LockQueue.cs
Normal file
95
DepthFirstScheduler/LockQueue.cs
Normal file
|
|
@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/LockQueue.cs.meta
Normal file
12
DepthFirstScheduler/LockQueue.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6b1eb436e400704ab6e2ad6eff29f4b
|
||||
timeCreated: 1519978475
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
150
DepthFirstScheduler/MainThreadDispatcher.cs
Normal file
150
DepthFirstScheduler/MainThreadDispatcher.cs
Normal file
|
|
@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/MainThreadDispatcher.cs.meta
Normal file
12
DepthFirstScheduler/MainThreadDispatcher.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b030a9507e46dd3488c080be0227b219
|
||||
timeCreated: 1519977925
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
47
DepthFirstScheduler/MonitorQueue.cs
Normal file
47
DepthFirstScheduler/MonitorQueue.cs
Normal file
|
|
@ -0,0 +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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/MonitorQueue.cs.meta
Normal file
12
DepthFirstScheduler/MonitorQueue.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5e968e04ff53e1c4a9a2869b7cf76055
|
||||
timeCreated: 1519990411
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
66
DepthFirstScheduler/README.md
Normal file
66
DepthFirstScheduler/README.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# DepthFirstScheduler(深さ優先スケジューラー)
|
||||
Asynchronous task scheduler for Unity-5.6 or later
|
||||
|
||||
これは、Unity5.6でTaskが無いことを補完するためのライブラリです。
|
||||
木構造にタスクを組み立てて深さ優先で消化します。
|
||||
|
||||
* タスクの実行スケジューラー(Unityメインスレッドやスレッドプール)を指定できる
|
||||
|
||||
# 使い方
|
||||
|
||||
```cs
|
||||
var schedulable = new Schedulable<Unit>();
|
||||
|
||||
schedulable
|
||||
.AddTask(Scheduler.ThreadPool, () => // 子供のタスクを追加する
|
||||
{
|
||||
return glTF_VRM_Material.Parse(ctx.Json);
|
||||
})
|
||||
.ContinueWith(Scheduler.MainThread, gltfMaterials => // 兄弟のタスクを追加する
|
||||
{
|
||||
ctx.MaterialImporter = new VRMMaterialImporter(ctx, gltfMaterials);
|
||||
})
|
||||
.Subscribe(Scheduler.MainThread, onLoaded, onError);
|
||||
;
|
||||
```
|
||||
|
||||
# Schedulable<T>
|
||||
T型の結果を返すタスク。
|
||||
|
||||
## AddTask(IScheduler scheduler, Func<T> firstTask)
|
||||
|
||||
子供のタスクを追加する。
|
||||
|
||||
ToDo: 一つ目の子供に引数を渡す手段が無い
|
||||
|
||||
## ContinueWith
|
||||
|
||||
## ContinueWithCoroutine
|
||||
|
||||
## OnExecute
|
||||
|
||||
動的にタスクを追加するためのHook。
|
||||
|
||||
中で、
|
||||
|
||||
```
|
||||
parent.AddTask
|
||||
```
|
||||
|
||||
することで実行時に子タスクを追加できる。
|
||||
|
||||
## Subscribe
|
||||
タスクの実行を開始する。
|
||||
実行結果を得る。
|
||||
|
||||
|
||||
# Scheduler
|
||||
## StepScheduler
|
||||
Unity
|
||||
## CurrentThreadScheduler
|
||||
即時
|
||||
## ThreadPoolScheduler
|
||||
スレッド
|
||||
## ThreadScheduler
|
||||
スレッド
|
||||
|
||||
8
DepthFirstScheduler/README.md.meta
Normal file
8
DepthFirstScheduler/README.md.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1231fa531fdd33f4baccc935c18c0872
|
||||
timeCreated: 1535290899
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
241
DepthFirstScheduler/Schedulable.cs
Normal file
241
DepthFirstScheduler/Schedulable.cs
Normal file
|
|
@ -0,0 +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
|
||||
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Schedulable.cs.meta
Normal file
12
DepthFirstScheduler/Schedulable.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 45e21e7db278f344fbaeffc4c4b82b1e
|
||||
timeCreated: 1519981307
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
DepthFirstScheduler/Scheduler.cs
Normal file
9
DepthFirstScheduler/Scheduler.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface IScheduler : IDisposable
|
||||
{
|
||||
void Enqueue(TaskChain item);
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Scheduler.cs.meta
Normal file
12
DepthFirstScheduler/Scheduler.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a160dc164df4094dbbc892055ac82ae
|
||||
timeCreated: 1520084097
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
DepthFirstScheduler/Scheduler.meta
Normal file
8
DepthFirstScheduler/Scheduler.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0700fb042f010694782d238049678651
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs
Normal file
102
DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler currentThread;
|
||||
|
||||
public static IScheduler CurrentThread
|
||||
{
|
||||
get { return currentThread ?? (currentThread = new CurrentThreadScheduler()); }
|
||||
}
|
||||
|
||||
public class CurrentThreadScheduler : IScheduler
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static Queue<TaskChain> queue;
|
||||
|
||||
private static Queue<TaskChain> GetQueue()
|
||||
{
|
||||
return queue;
|
||||
}
|
||||
|
||||
private static void SetQueue(Queue<TaskChain> newQueue)
|
||||
{
|
||||
queue = newQueue;
|
||||
}
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
var q = GetQueue();
|
||||
|
||||
if (q == null)
|
||||
{
|
||||
q = new Queue<TaskChain>(5);
|
||||
q.Enqueue(item);
|
||||
SetQueue(q);
|
||||
|
||||
try
|
||||
{
|
||||
Trampoline.Run(q);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetQueue(null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
q.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
|
||||
private bool disposedValue = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
var queue = GetQueue();
|
||||
if (queue != null) queue.Clear();
|
||||
SetQueue(null);
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
static class Trampoline
|
||||
{
|
||||
public static void Run(Queue<TaskChain> queue)
|
||||
{
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var chain = queue.Dequeue();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = chain.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs.meta
Normal file
11
DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 21979cc7137a17d4ea8b6202381a02d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
DepthFirstScheduler/Scheduler/StepScheduler.cs
Normal file
52
DepthFirstScheduler/Scheduler/StepScheduler.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static StepScheduler mainThread;
|
||||
|
||||
public static StepScheduler MainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mainThread != null) return mainThread;
|
||||
mainThread = new StepScheduler();
|
||||
MainThreadDispatcher.Initialize();
|
||||
return mainThread;
|
||||
}
|
||||
}
|
||||
|
||||
public class StepScheduler : IScheduler
|
||||
{
|
||||
LockQueue<TaskChain> m_taskQueue = new LockQueue<TaskChain>();
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
m_taskQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
TaskChain m_chain;
|
||||
|
||||
public int UpdateAndGetTaskCount()
|
||||
{
|
||||
if (m_chain != null)
|
||||
{
|
||||
var status = m_chain.Next();
|
||||
if (status == ExecutionStatus.Continue)
|
||||
{
|
||||
// m_item継続中
|
||||
return m_taskQueue.Count;
|
||||
}
|
||||
m_chain = null;
|
||||
}
|
||||
|
||||
int count;
|
||||
m_chain = m_taskQueue.Dequeue(out count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Scheduler/StepScheduler.cs.meta
Normal file
12
DepthFirstScheduler/Scheduler/StepScheduler.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 84161938c020c37419bc79f021f849fb
|
||||
timeCreated: 1520062584
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs
Normal file
42
DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler threadPool;
|
||||
|
||||
public static IScheduler ThreadPool
|
||||
{
|
||||
get { return threadPool ?? (threadPool = new ThreadPoolScheduler()); }
|
||||
}
|
||||
|
||||
public class ThreadPoolScheduler : IScheduler
|
||||
{
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = item.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs.meta
Normal file
12
DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d8a8d78a486bbdf4b95ae83d02b480d8
|
||||
timeCreated: 1524110819
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
101
DepthFirstScheduler/Scheduler/ThreadScheduler.cs
Normal file
101
DepthFirstScheduler/Scheduler/ThreadScheduler.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler singleWorkerThread;
|
||||
|
||||
public static IScheduler SingleWorkerThread
|
||||
{
|
||||
get { return singleWorkerThread ?? (singleWorkerThread = new ThreadScheduler()); }
|
||||
}
|
||||
|
||||
public class ThreadScheduler : IScheduler
|
||||
{
|
||||
MonitorQueue<TaskChain> m_queue = new MonitorQueue<TaskChain>();
|
||||
|
||||
Thread m_thread;
|
||||
|
||||
public ThreadScheduler()
|
||||
{
|
||||
// start worker thread
|
||||
m_thread = new Thread(new ParameterizedThreadStart(Worker));
|
||||
m_thread.Start(m_queue);
|
||||
}
|
||||
|
||||
static void Worker(Object arg)
|
||||
{
|
||||
MonitorQueue<TaskChain> queue = (MonitorQueue<TaskChain>)arg;
|
||||
while (true)
|
||||
{
|
||||
var chain = queue.Dequeue();
|
||||
if (chain == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = chain.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
}
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
m_queue.Enqueue(item);
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
|
||||
private bool disposedValue = false; // 重複する呼び出しを検出するには
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
|
||||
if (m_thread != null)
|
||||
{
|
||||
m_queue.Enqueue(null);
|
||||
m_thread.Join();
|
||||
m_thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
|
||||
// TODO: 大きなフィールドを null に設定します。
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
|
||||
// ~ThreadScheduler() {
|
||||
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
|
||||
public void Dispose()
|
||||
{
|
||||
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
Dispose(true);
|
||||
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Scheduler/ThreadScheduler.cs.meta
Normal file
12
DepthFirstScheduler/Scheduler/ThreadScheduler.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8df1de98bdc0b534bbe68e8f2f8a858f
|
||||
timeCreated: 1520062592
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
DepthFirstScheduler/TaskChain.cs
Normal file
91
DepthFirstScheduler/TaskChain.cs
Normal file
|
|
@ -0,0 +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();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/TaskChain.cs.meta
Normal file
12
DepthFirstScheduler/TaskChain.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38fc7e076ba93a847ad72d3d459d06b6
|
||||
timeCreated: 1520084019
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
DepthFirstScheduler/Unit.cs
Normal file
41
DepthFirstScheduler/Unit.cs
Normal file
|
|
@ -0,0 +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 "()";
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DepthFirstScheduler/Unit.cs.meta
Normal file
12
DepthFirstScheduler/Unit.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 98bd42f8c3a895d4bac6cbcf523878bb
|
||||
timeCreated: 1520081817
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user