fixed some race conditions with nested coroutines

This commit is contained in:
Ell 2021-03-17 01:13:57 +01:00
parent ffdb5ed8f7
commit 6e07a26a6c
2 changed files with 30 additions and 23 deletions

View file

@ -124,7 +124,7 @@ namespace Coroutine {
/// <inheritdoc /> /// <inheritdoc />
public int CompareTo(ActiveCoroutine other) { public int CompareTo(ActiveCoroutine other) {
return this.Priority.CompareTo(other.Priority); return other.Priority.CompareTo(this.Priority);
} }
} }

View file

@ -12,6 +12,7 @@ namespace Coroutine {
private readonly List<ActiveCoroutine> tickingCoroutines = new List<ActiveCoroutine>(); private readonly List<ActiveCoroutine> tickingCoroutines = new List<ActiveCoroutine>();
private readonly List<ActiveCoroutine> eventCoroutines = new List<ActiveCoroutine>(); private readonly List<ActiveCoroutine> eventCoroutines = new List<ActiveCoroutine>();
private readonly Queue<ActiveCoroutine> outstandingCoroutines = new Queue<ActiveCoroutine>();
private readonly Stopwatch stopwatch = new Stopwatch(); private readonly Stopwatch stopwatch = new Stopwatch();
/// <summary> /// <summary>
@ -45,7 +46,7 @@ namespace Coroutine {
public ActiveCoroutine Start(IEnumerator<Wait> coroutine, string name = "", int priority = 0) { public ActiveCoroutine Start(IEnumerator<Wait> coroutine, string name = "", int priority = 0) {
var inst = new ActiveCoroutine(coroutine, name, priority, this.stopwatch); var inst = new ActiveCoroutine(coroutine, name, priority, this.stopwatch);
if (inst.MoveNext()) if (inst.MoveNext())
AddSorted(inst.IsWaitingForEvent() ? this.eventCoroutines : this.tickingCoroutines, inst); this.outstandingCoroutines.Enqueue(inst);
return inst; return inst;
} }
@ -67,15 +68,16 @@ namespace Coroutine {
/// </summary> /// </summary>
/// <param name="deltaSeconds">The amount of seconds that have passed since the last time this method was invoked</param> /// <param name="deltaSeconds">The amount of seconds that have passed since the last time this method was invoked</param>
public void Tick(double deltaSeconds) { public void Tick(double deltaSeconds) {
for (var i = this.tickingCoroutines.Count - 1; i >= 0; i--) { this.AddOutstandingCoroutines();
var coroutine = this.tickingCoroutines[i]; this.tickingCoroutines.RemoveAll(c => {
if (coroutine.Tick(deltaSeconds)) { if (c.Tick(deltaSeconds)) {
this.tickingCoroutines.RemoveAt(i); return true;
} else if (coroutine.IsWaitingForEvent()) { } else if (c.IsWaitingForEvent()) {
this.tickingCoroutines.RemoveAt(i); this.outstandingCoroutines.Enqueue(c);
this.eventCoroutines.Add(coroutine); return true;
} }
} return false;
});
} }
/// <summary> /// <summary>
@ -83,15 +85,16 @@ namespace Coroutine {
/// </summary> /// </summary>
/// <param name="evt">The event to raise</param> /// <param name="evt">The event to raise</param>
public void RaiseEvent(Event evt) { public void RaiseEvent(Event evt) {
for (var i = this.eventCoroutines.Count - 1; i >= 0; i--) { this.AddOutstandingCoroutines();
var coroutine = this.eventCoroutines[i]; this.eventCoroutines.RemoveAll(c => {
if (coroutine.OnEvent(evt)) { if (c.OnEvent(evt)) {
this.eventCoroutines.RemoveAt(i); return true;
} else if (!coroutine.IsWaitingForEvent()) { } else if (!c.IsWaitingForEvent()) {
this.eventCoroutines.RemoveAt(i); this.outstandingCoroutines.Enqueue(c);
this.tickingCoroutines.Add(coroutine); return true;
} }
} return false;
});
} }
/// <summary> /// <summary>
@ -102,15 +105,19 @@ namespace Coroutine {
return this.tickingCoroutines.Concat(this.eventCoroutines); return this.tickingCoroutines.Concat(this.eventCoroutines);
} }
private void AddOutstandingCoroutines() {
while (this.outstandingCoroutines.Count > 0) {
var coroutine = this.outstandingCoroutines.Dequeue();
var list = coroutine.IsWaitingForEvent() ? this.eventCoroutines : this.tickingCoroutines;
var position = list.BinarySearch(coroutine);
list.Insert(position < 0 ? ~position : position, coroutine);
}
}
private static IEnumerator<Wait> InvokeLaterImpl(Wait wait, Action action) { private static IEnumerator<Wait> InvokeLaterImpl(Wait wait, Action action) {
yield return wait; yield return wait;
action(); action();
} }
private static void AddSorted(List<ActiveCoroutine> list, ActiveCoroutine coroutine) {
var position = list.BinarySearch(coroutine);
list.Insert(position < 0 ? ~position : position, coroutine);
}
} }
} }