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

TestWorker

public class TestWorker
A TestWorker pulls work items from a queue and executes them.
using System; using System.Runtime.CompilerServices; using System.Threading; namespace NUnit.Framework.Internal.Execution { [NullableContext(1)] [Nullable(0)] public class TestWorker { [NullableContext(0)] public delegate void TestWorkerEventHandler (TestWorker worker, WorkItem work); private static readonly Logger Log = InternalTrace.GetLogger("TestWorker"); [Nullable(2)] private Thread _workerThread; private int _workItemCount; private bool _running; [Nullable(2)] private WorkItem _currentWorkItem; private readonly object _cancelLock = new object(); public WorkItemQueue WorkQueue { get; } public string Name { get; } public bool IsAlive => _workerThread?.IsAlive ?? false; [Nullable(2)] [method: NullableContext(2)] [field: Nullable(2)] public event TestWorkerEventHandler Busy; [Nullable(2)] [method: NullableContext(2)] [field: Nullable(2)] public event TestWorkerEventHandler Idle; public TestWorker(WorkItemQueue queue, string name) { Guard.ArgumentNotNull(queue, "queue"); WorkQueue = queue; Name = name; } private void TestWorkerThreadProc() { _running = true; try { while (_running) { _currentWorkItem = WorkQueue.Dequeue(); if (_currentWorkItem == null) break; Log.Info("{0} executing {1}", Thread.CurrentThread.Name, _currentWorkItem.Name); _currentWorkItem.TestWorker = this; this.Busy?.Invoke(this, _currentWorkItem); _currentWorkItem.Execute(); this.Idle?.Invoke(this, _currentWorkItem); _workItemCount++; } } finally { Log.Info("{0} stopping - {1} WorkItems processed.", Name, _workItemCount); } } public void Start() { _workerThread = new Thread(TestWorkerThreadProc) { Name = Name }; if (OperatingSystem.IsWindows()) _workerThread.SetApartmentState(WorkQueue.TargetApartment); Log.Info("{0} starting on thread [{1}]", Name, _workerThread.ManagedThreadId); _workerThread.Start(); } public void Cancel(bool force) { if (force) _running = false; lock (_cancelLock) { if (_workerThread != null && _currentWorkItem != null) { _currentWorkItem.Cancel(force); if (force) _currentWorkItem = null; } } } } }