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

TestWorker

public class TestWorker
A TestWorker pulls work items from a queue and executes them.
using System; using System.Threading; namespace NUnit.Framework.Internal.Execution { public class TestWorker { private static Logger log = InternalTrace.GetLogger("TestWorker"); private WorkItemQueue _readyQueue; private Thread _workerThread; private int _workItemCount; private bool _running; private WorkItem _currentWorkItem; private object cancelLock = new object(); public string Name => _workerThread.Name; public bool IsAlive => _workerThread.IsAlive; public event EventHandler Busy; public event EventHandler Idle; public TestWorker(WorkItemQueue queue, string name, ApartmentState apartmentState) { _readyQueue = queue; _workerThread = new Thread(TestWorkerThreadProc); _workerThread.Name = name; _workerThread.SetApartmentState(apartmentState); } private void TestWorkerThreadProc() { log.Info("{0} starting ", _workerThread.Name); _running = true; try { while (_running) { _currentWorkItem = _readyQueue.Dequeue(); if (_currentWorkItem == null) break; log.Info("{0} executing {1}", _workerThread.Name, _currentWorkItem.Test.Name); if (this.Busy != null) this.Busy(this, EventArgs.Empty); _currentWorkItem.WorkerId = Name; _currentWorkItem.Execute(); if (this.Idle != null) this.Idle(this, EventArgs.Empty); _workItemCount++; } } finally { log.Info("{0} stopping - {1} WorkItems processed.", _workerThread.Name, _workItemCount); } } public void Start() { _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; } } } } }