#if !NETSTANDARD1_3 using System; using System.Collections.Generic; using System.Threading; namespace Unosquare.Swan.Abstractions { /// /// 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(Boolean isEnabled) { this.Name = this.GetType().Name; this.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 Boolean IsRunning { get; private set; } /// /// Gets a value indicating whether this instance is enabled. /// /// /// true if this instance is enabled; otherwise, false. /// public Boolean IsEnabled { get; } /// /// Starts this instance. /// public virtual void Start() { if(this.IsEnabled == false) { return; } $"Start Requested".Debug(this.Name); this._cancelTokenSource = new CancellationTokenSource(); this._workFinished = new ManualResetEvent(false); this._worker = new Thread(() => { _ = this._workFinished.Reset(); this.IsRunning = true; try { this.Setup(); this.DoBackgroundWork(this._cancelTokenSource.Token); } catch(ThreadAbortException) { $"{nameof(ThreadAbortException)} caught.".Warn(this.Name); } catch(Exception ex) { $"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}".Error(this.Name); } finally { this.Cleanup(); _ = this._workFinished?.Set(); this.IsRunning = false; "Stopped Completely".Debug(this.Name); } }) { IsBackground = true, Name = $"{this.Name}Thread", }; this._worker.Start(); } /// /// Stops this instance. /// public virtual void Stop() { if(this.IsEnabled == false || this.IsRunning == false) { return; } $"Stop Requested".Debug(this.Name); this._cancelTokenSource.Cancel(); Int32 waitRetries = 5; while(waitRetries >= 1) { if(this._workFinished.WaitOne(250)) { waitRetries = -1; break; } waitRetries--; } if(waitRetries < 0) { "Workbench stopped gracefully".Debug(this.Name); } else { "Did not respond to stop request. Aborting thread and waiting . . .".Warn(this.Name); this._worker.Abort(); if(this._workFinished.WaitOne(5000) == false) { "Waited and no response. Worker might have been left in an inconsistent state.".Error(this.Name); } else { "Waited for worker and it finally responded (OK).".Debug(this.Name); } } this._workFinished.Dispose(); this._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