ensure coroutine handler instance thread safety

This commit is contained in:
Ell 2021-11-29 11:37:17 +01:00
parent f71426321f
commit 1deb8a9d89

View file

@ -16,15 +16,26 @@ namespace Coroutine {
private readonly HashSet<ActiveCoroutine> outstandingEventCoroutines = new HashSet<ActiveCoroutine>(); private readonly HashSet<ActiveCoroutine> outstandingEventCoroutines = new HashSet<ActiveCoroutine>();
private readonly HashSet<ActiveCoroutine> outstandingTickingCoroutines = new HashSet<ActiveCoroutine>(); private readonly HashSet<ActiveCoroutine> outstandingTickingCoroutines = new HashSet<ActiveCoroutine>();
private readonly Stopwatch stopwatch = new Stopwatch(); private readonly Stopwatch stopwatch = new Stopwatch();
private readonly object lockObject = new object();
/// <summary> /// <summary>
/// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for a tick (waiting for time to pass) /// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for a tick (waiting for time to pass)
/// </summary> /// </summary>
public int TickingCount => this.tickingCoroutines.Count; public int TickingCount {
get {
lock (this.lockObject)
return this.tickingCoroutines.Count;
}
}
/// <summary> /// <summary>
/// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for an <see cref="Event"/> /// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for an <see cref="Event"/>
/// </summary> /// </summary>
public int EventCount => this.eventCoroutines.Sum(c => c.Value.Count); public int EventCount {
get {
lock (this.lockObject)
return this.eventCoroutines.Sum(c => c.Value.Count);
}
}
/// <summary> /// <summary>
/// Starts the given coroutine, returning a <see cref="ActiveCoroutine"/> object for management. /// Starts the given coroutine, returning a <see cref="ActiveCoroutine"/> object for management.
@ -47,8 +58,10 @@ namespace Coroutine {
/// <returns>An active coroutine object representing this coroutine</returns> /// <returns>An active coroutine object representing this coroutine</returns>
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()) {
lock (this.lockObject)
this.GetOutstandingCoroutines(inst.IsWaitingForEvent).Add(inst); this.GetOutstandingCoroutines(inst.IsWaitingForEvent).Add(inst);
}
return inst; return inst;
} }
@ -70,6 +83,7 @@ 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) {
lock (this.lockObject) {
this.MoveOutstandingCoroutines(false); this.MoveOutstandingCoroutines(false);
this.tickingCoroutines.RemoveAll(c => { this.tickingCoroutines.RemoveAll(c => {
if (c.Tick(deltaSeconds)) { if (c.Tick(deltaSeconds)) {
@ -81,6 +95,7 @@ namespace Coroutine {
return false; return false;
}); });
} }
}
/// <summary> /// <summary>
/// Ticks this coroutine handler, causing all time-based <see cref="Wait"/>s to be ticked. /// Ticks this coroutine handler, causing all time-based <see cref="Wait"/>s to be ticked.
@ -96,6 +111,7 @@ 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) {
lock (this.lockObject) {
this.MoveOutstandingCoroutines(true); this.MoveOutstandingCoroutines(true);
var coroutines = this.GetEventCoroutines(evt, false); var coroutines = this.GetEventCoroutines(evt, false);
if (coroutines != null) { if (coroutines != null) {
@ -113,12 +129,14 @@ namespace Coroutine {
} }
} }
} }
}
/// <summary> /// <summary>
/// Returns a list of all currently active <see cref="ActiveCoroutine"/> objects under this handler. /// Returns a list of all currently active <see cref="ActiveCoroutine"/> objects under this handler.
/// </summary> /// </summary>
/// <returns>All active coroutines</returns> /// <returns>All active coroutines</returns>
public IEnumerable<ActiveCoroutine> GetActiveCoroutines() { public IEnumerable<ActiveCoroutine> GetActiveCoroutines() {
lock (this.lockObject)
return this.tickingCoroutines.Concat(this.eventCoroutines.Values.SelectMany(c => c)); return this.tickingCoroutines.Concat(this.eventCoroutines.Values.SelectMany(c => c));
} }