From 6e07a26a6cb351e6abd482b062e7301e80ae2c85 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 17 Mar 2021 01:13:57 +0100 Subject: [PATCH] fixed some race conditions with nested coroutines --- Coroutine/ActiveCoroutine.cs | 2 +- Coroutine/CoroutineHandlerInstance.cs | 51 +++++++++++++++------------ 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Coroutine/ActiveCoroutine.cs b/Coroutine/ActiveCoroutine.cs index 17a95a9..5604593 100644 --- a/Coroutine/ActiveCoroutine.cs +++ b/Coroutine/ActiveCoroutine.cs @@ -124,7 +124,7 @@ namespace Coroutine { /// public int CompareTo(ActiveCoroutine other) { - return this.Priority.CompareTo(other.Priority); + return other.Priority.CompareTo(this.Priority); } } diff --git a/Coroutine/CoroutineHandlerInstance.cs b/Coroutine/CoroutineHandlerInstance.cs index 4aa2f24..5db850c 100644 --- a/Coroutine/CoroutineHandlerInstance.cs +++ b/Coroutine/CoroutineHandlerInstance.cs @@ -12,6 +12,7 @@ namespace Coroutine { private readonly List tickingCoroutines = new List(); private readonly List eventCoroutines = new List(); + private readonly Queue outstandingCoroutines = new Queue(); private readonly Stopwatch stopwatch = new Stopwatch(); /// @@ -45,7 +46,7 @@ namespace Coroutine { public ActiveCoroutine Start(IEnumerator coroutine, string name = "", int priority = 0) { var inst = new ActiveCoroutine(coroutine, name, priority, this.stopwatch); if (inst.MoveNext()) - AddSorted(inst.IsWaitingForEvent() ? this.eventCoroutines : this.tickingCoroutines, inst); + this.outstandingCoroutines.Enqueue(inst); return inst; } @@ -67,15 +68,16 @@ namespace Coroutine { /// /// The amount of seconds that have passed since the last time this method was invoked public void Tick(double deltaSeconds) { - for (var i = this.tickingCoroutines.Count - 1; i >= 0; i--) { - var coroutine = this.tickingCoroutines[i]; - if (coroutine.Tick(deltaSeconds)) { - this.tickingCoroutines.RemoveAt(i); - } else if (coroutine.IsWaitingForEvent()) { - this.tickingCoroutines.RemoveAt(i); - this.eventCoroutines.Add(coroutine); + this.AddOutstandingCoroutines(); + this.tickingCoroutines.RemoveAll(c => { + if (c.Tick(deltaSeconds)) { + return true; + } else if (c.IsWaitingForEvent()) { + this.outstandingCoroutines.Enqueue(c); + return true; } - } + return false; + }); } /// @@ -83,15 +85,16 @@ namespace Coroutine { /// /// The event to raise public void RaiseEvent(Event evt) { - for (var i = this.eventCoroutines.Count - 1; i >= 0; i--) { - var coroutine = this.eventCoroutines[i]; - if (coroutine.OnEvent(evt)) { - this.eventCoroutines.RemoveAt(i); - } else if (!coroutine.IsWaitingForEvent()) { - this.eventCoroutines.RemoveAt(i); - this.tickingCoroutines.Add(coroutine); + this.AddOutstandingCoroutines(); + this.eventCoroutines.RemoveAll(c => { + if (c.OnEvent(evt)) { + return true; + } else if (!c.IsWaitingForEvent()) { + this.outstandingCoroutines.Enqueue(c); + return true; } - } + return false; + }); } /// @@ -102,15 +105,19 @@ namespace Coroutine { 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 InvokeLaterImpl(Wait wait, Action action) { yield return wait; action(); } - private static void AddSorted(List list, ActiveCoroutine coroutine) { - var position = list.BinarySearch(coroutine); - list.Insert(position < 0 ? ~position : position, coroutine); - } - } } \ No newline at end of file