MainThreadDispatcher.cs
3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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.MainThreadDispatcher");
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;
}
}
}