<PackageReference Include="NUnit" Version="4.3.0" />

EventQueue<T>

public abstract class EventQueue<T>
Implements a template for a queue of work items each of which is queued as a WaitCallback. It can handle any event types.
using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Threading; namespace NUnit.Framework.Internal.Execution { [NullableContext(1)] [Nullable(0)] public abstract class EventQueue<[Nullable(2)] T> { private const int SpinCount = 5; private readonly ConcurrentQueue<T> _queue = new ConcurrentQueue<T>(); private readonly ManualResetEventSlim _mreAdd = new ManualResetEventSlim(); private int _addId = -2147483648; private int _removeId = -2147483648; private int _stopped; public int Count => _queue.Count; public void Enqueue(T e) { int addId; do { addId = _addId; } while (Interlocked.CompareExchange(ref _addId, addId + 1, addId) != addId); _queue.Enqueue(e); _mreAdd.Set(); Thread.Sleep(0); } [NullableContext(2)] public T Dequeue(bool blockWhenEmpty) { SpinWait spinWait = default(SpinWait); while (true) { int removeId = _removeId; int addId = _addId; if (removeId == addId) { if (!blockWhenEmpty || _stopped != 0) return default(T); if (spinWait.Count <= 5) spinWait.SpinOnce(); else { _mreAdd.Reset(); if (removeId != _removeId || addId != _addId) _mreAdd.Set(); else _mreAdd.Wait(500); } } else if (Interlocked.CompareExchange(ref _removeId, removeId + 1, removeId) == removeId) { break; } } T result; while (!_queue.TryDequeue(out result)) { if (!blockWhenEmpty || _stopped != 0) return default(T); } return result; } public void Stop() { if (Interlocked.CompareExchange(ref _stopped, 1, 0) == 0) _mreAdd.Set(); } } }