#if !NETSTANDARD1_3 namespace Unosquare.Swan.Abstractions { using System; using System.Collections.Generic; using System.Threading; using Swan; /// /// Represents an background worker abstraction with a life cycle and running at a independent thread. /// public abstract class RunnerBase { private Thread _worker; private CancellationTokenSource _cancelTokenSource; private ManualResetEvent _workFinished; /// /// Initializes a new instance of the class. /// /// if set to true [is enabled]. protected RunnerBase(bool isEnabled) { Name = GetType().Name; IsEnabled = isEnabled; } /// /// Gets the error messages. /// /// /// The error messages. /// public List ErrorMessages { get; } = new List(); /// /// Gets the name. /// /// /// The name. /// public string Name { get; } /// /// Gets a value indicating whether this instance is running. /// /// /// true if this instance is running; otherwise, false. /// public bool IsRunning { get; private set; } /// /// Gets a value indicating whether this instance is enabled. /// /// /// true if this instance is enabled; otherwise, false. /// public bool IsEnabled { get; } /// /// Starts this instance. /// public virtual void Start() { if (IsEnabled == false) return; $"Start Requested".Debug(Name); _cancelTokenSource = new CancellationTokenSource(); _workFinished = new ManualResetEvent(false); _worker = new Thread(() => { _workFinished.Reset(); IsRunning = true; try { Setup(); DoBackgroundWork(_cancelTokenSource.Token); } catch (ThreadAbortException) { $"{nameof(ThreadAbortException)} caught.".Warn(Name); } catch (Exception ex) { $"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}".Error(Name); } finally { Cleanup(); _workFinished?.Set(); IsRunning = false; "Stopped Completely".Debug(Name); } }) { IsBackground = true, Name = $"{Name}Thread", }; _worker.Start(); } /// /// Stops this instance. /// public virtual void Stop() { if (IsEnabled == false || IsRunning == false) return; $"Stop Requested".Debug(Name); _cancelTokenSource.Cancel(); var waitRetries = 5; while (waitRetries >= 1) { if (_workFinished.WaitOne(250)) { waitRetries = -1; break; } waitRetries--; } if (waitRetries < 0) { "Workbench stopped gracefully".Debug(Name); } else { "Did not respond to stop request. Aborting thread and waiting . . .".Warn(Name); _worker.Abort(); if (_workFinished.WaitOne(5000) == false) "Waited and no response. Worker might have been left in an inconsistent state.".Error(Name); else "Waited for worker and it finally responded (OK).".Debug(Name); } _workFinished.Dispose(); _workFinished = null; } /// /// Setups this instance. /// protected virtual void Setup() { // empty } /// /// Cleanups this instance. /// protected virtual void Cleanup() { // empty } /// /// Does the background work. /// /// The ct. protected abstract void DoBackgroundWork(CancellationToken ct); } } #endif