#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