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

WorkItemQueue

public class WorkItemQueue
A WorkItemQueue holds work items that are ready to be run, either initially or after some dependency has been satisfied.
using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; using System.Threading; namespace NUnit.Framework.Internal.Execution { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class WorkItemQueue { [System.Runtime.CompilerServices.Nullable(0)] private class SavedState { public readonly ConcurrentQueue<WorkItem>[] InnerQueues; public readonly int AddId; public readonly int RemoveId; public SavedState(WorkItemQueue queue) { InnerQueues = queue._innerQueues; AddId = queue._addId; RemoveId = queue._removeId; } } private const int SPIN_COUNT = 5; private const int HIGH_PRIORITY = 0; private const int NORMAL_PRIORITY = 1; private const int PRIORITY_LEVELS = 2; private readonly Logger _log = InternalTrace.GetLogger("WorkItemQueue"); private ConcurrentQueue<WorkItem>[] _innerQueues; private readonly Stack<SavedState> _savedState = new Stack<SavedState>(); private readonly ManualResetEventSlim _mreAdd = new ManualResetEventSlim(); private int _addId = -2147483648; private int _removeId = -2147483648; private int _itemsProcessed; private int _state; public string Name { get; } public bool IsParallelQueue { get; } public ApartmentState TargetApartment { get; } public int ItemsProcessed { get { return _itemsProcessed; } private set { _itemsProcessed = value; } } public WorkItemQueueState State { get { return (WorkItemQueueState)_state; } private set { _state = (int)value; } } public bool IsEmpty { get { ConcurrentQueue<WorkItem>[] innerQueues = _innerQueues; foreach (ConcurrentQueue<WorkItem> concurrentQueue in innerQueues) { if (!concurrentQueue.IsEmpty) return false; } return true; } } public WorkItemQueue(string name, bool isParallel, ApartmentState apartment) { Name = name; IsParallelQueue = isParallel; TargetApartment = apartment; State = WorkItemQueueState.Paused; ItemsProcessed = 0; InitializeQueues(); } [MemberNotNull("_innerQueues")] private void InitializeQueues() { ConcurrentQueue<WorkItem>[] array = new ConcurrentQueue<WorkItem>[2]; for (int i = 0; i < 2; i++) { array[i] = new ConcurrentQueue<WorkItem>(); } _innerQueues = array; _addId = (_removeId = 0); } public void Enqueue(WorkItem work) { Enqueue(work, (!(work is CompositeWorkItem.OneTimeTearDownWorkItem)) ? 1 : 0); } internal void Enqueue(WorkItem work, int priority) { Guard.ArgumentInRange(priority >= 0 && priority < 2, "Invalid priority specified", "priority"); int addId; do { addId = _addId; } while (Interlocked.CompareExchange(ref _addId, addId + 1, addId) != addId); _innerQueues[priority].Enqueue(work); _mreAdd.Set(); } [System.Runtime.CompilerServices.NullableContext(2)] public WorkItem Dequeue() { SpinWait spinWait = default(SpinWait); while (true) { WorkItemQueueState state = State; if (state == WorkItemQueueState.Stopped) return null; int removeId = _removeId; int addId = _addId; if (removeId == addId || state == WorkItemQueueState.Paused) { if (spinWait.Count <= 5) spinWait.SpinOnce(); else { _mreAdd.Reset(); if ((removeId != _removeId || addId != _addId) && state != 0) _mreAdd.Set(); else _mreAdd.Wait(500); } } else if (Interlocked.CompareExchange(ref _removeId, removeId + 1, removeId) == removeId) { break; } } WorkItem result = null; while (result == null) { ConcurrentQueue<WorkItem>[] innerQueues = _innerQueues; foreach (ConcurrentQueue<WorkItem> concurrentQueue in innerQueues) { if (concurrentQueue.TryDequeue(out result)) break; } } Interlocked.Increment(ref _itemsProcessed); return result; } public void Start() { _log.Info("{0}.{1} starting", Name, _savedState.Count); if (Interlocked.CompareExchange(ref _state, 1, 0) == 0) _mreAdd.Set(); } public void Stop() { _log.Info("{0}.{1} stopping - {2} WorkItems processed", Name, _savedState.Count, ItemsProcessed); if (Interlocked.Exchange(ref _state, 2) != 2) _mreAdd.Set(); } public void Pause() { _log.Debug("{0}.{1} pausing", Name, _savedState.Count); Interlocked.CompareExchange(ref _state, 0, 1); } internal void Save() { bool flag = State == WorkItemQueueState.Running; if (flag) Pause(); _savedState.Push(new SavedState(this)); InitializeQueues(); if (flag) Start(); } internal void Restore() { SavedState savedState = _savedState.Pop(); for (int i = 0; i < 2; i++) { WorkItem result; while (_innerQueues[i].TryDequeue(out result)) { savedState.InnerQueues[i].Enqueue(result); } } _innerQueues = savedState.InnerQueues; _addId += savedState.AddId; _removeId += savedState.RemoveId; } internal string DumpContents() { StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(32, 2, stringBuilder2); handler.AppendLiteral("Contents of "); handler.AppendFormatted(Name); handler.AppendLiteral(" at isolation level "); handler.AppendFormatted(_savedState.Count); stringBuilder3.AppendLine(ref handler); if (IsEmpty) stringBuilder.AppendLine(" <empty>"); else { for (int i = 0; i < 2; i++) { foreach (WorkItem item in _innerQueues[i]) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(6, 2, stringBuilder2); handler.AppendLiteral("pri-"); handler.AppendFormatted(i); handler.AppendLiteral(": "); handler.AppendFormatted(item.Name); stringBuilder4.AppendLine(ref handler); } } } int num = 0; foreach (SavedState item2 in _savedState) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2); handler.AppendLiteral("Saved State "); handler.AppendFormatted(num++); stringBuilder5.AppendLine(ref handler); bool flag = true; for (int j = 0; j < 2; j++) { foreach (WorkItem item3 in item2.InnerQueues[j]) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(6, 2, stringBuilder2); handler.AppendLiteral("pri-"); handler.AppendFormatted(j); handler.AppendLiteral(": "); handler.AppendFormatted(item3.Name); stringBuilder6.AppendLine(ref handler); flag = false; } } if (flag) stringBuilder.AppendLine(" <empty>"); } return stringBuilder.ToString(); } } }