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();
}
}
}