|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace MefBasic.Threading
{
public class Job
{
private int _maxWaitTimeToStop;
public Action<Job> JobAction { get; private set; }
public Action<JobProgressArgs> ProgressNotifyAction { get; private set; }
public event EventHandler JobCompleted;
public event CancelEventHandler StartingJob;
protected List<string> DependentJobs { get; set; }
protected void InvokeStartingJob(CancelEventArgs e)
{
if (StartingJob != null)
StartingJob(this, e);
}
public bool IsThreadSafe { get; set; }
public JobStore Store { get; set; }
public string Id { get; set; }
public AutoResetEvent WaitEvent { private set; get; }
public Job(Action<Job> jobAction)
: this(jobAction, null)
{
MaxWaitTimeToStop = 5000;
}
public Job Dependency(params string [] dependentJobs)
{
DependentJobs.AddRange(dependentJobs);
return this;
}
public Job(Action<Job> jobAction, Action<JobProgressArgs> progressNotifyAction)
{
ProgressNotifyAction = progressNotifyAction;
JobAction = jobAction;
Id = Guid.NewGuid().ToString();
WaitEvent = new AutoResetEvent(false);
Store = new JobStore {Status = JobStatus.NotStarted};
ChildreenJob = new List<Job>();
IsThreadSafe = true;
DependentJobs=new List<string>();
}
protected void OnJobCompleted(EventArgs e)
{
switch (Store.Status)
{
case JobStatus.AbortRequested:
Store.Status = JobStatus.Aborted;
break;
case JobStatus.Started:
Store.Status = JobStatus.Completed;
break;
}
IsComplete = true;
if (JobCompleted != null)
JobCompleted(this, e);
}
protected void OnProgressAction(JobProgressArgs args)
{
if (ProgressNotifyAction != null)
{
ProgressNotifyAction(args);
}
}
public virtual void Start()
{
if(InvokeStartingJob())
return;
DoStart();
}
public void Resume()
{
if (Store.PauseRequested)
{
Store.PauseRequested = false;
Store.Status = JobStatus.Started;
return;
}
}
protected void DoStart()
{
Store.Status = JobStatus.Started;
WaitEvent.Reset();
if (IsThreadSafe)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) => DoWork(e.Argument);
worker.RunWorkerCompleted += (s, e) =>
{
WaitEvent.Set();
OnJobCompleted(new EventArgs());
};
worker.RunWorkerAsync(this);
}
else
{
DoWork(this);
WaitEvent.Set();
OnJobCompleted(new EventArgs());
}
}
protected bool InvokeStartingJob()
{
var cancelEventArgs = new CancelEventArgs(false);
InvokeStartingJob(cancelEventArgs);
var isCancelled = cancelEventArgs.Cancel;
if(isCancelled)
{
Store.Status = JobStatus.Aborted;
WaitEvent.Set();
OnJobCompleted(new EventArgs());
}
return isCancelled;
}
private void DoWork(object args)
{
WaitForDependentJobs();
var job = (Job) args;
if (ChildreenJob.Count > 0)
{
foreach (var childJob in ChildreenJob)
{
childJob.Start();
}
ChildreenJob.ForEach(c=>c.Wait());
}
if(JobAction!=null)
JobAction(job);
}
protected void WaitForDependentJobs()
{
foreach (var dependentJob in DependentJobs)
{
Parent.GetChild(dependentJob).Wait();
}
}
public bool IsComplete { get; protected set; }
public void Wait()
{
if (IsComplete) return;
if (IsComplete == false)
{
WaitEvent.WaitOne();
WaitEvent.Set();
}
}
protected List<Job> ChildreenJob { get; set; }
public void AddChild(Job childJob)
{
childJob.Parent = this;
ChildreenJob.Add(childJob);
}
public Job Parent { get; set; }
public Job Root
{
get
{
return Parent == null ? this : Parent.Root;
}
}
public int MaxWaitTimeToStop
{
get { return _maxWaitTimeToStop; }
set { _maxWaitTimeToStop = value; }
}
public IEnumerable<Job> GetChildreen()
{
return ChildreenJob;
}
public void NotifyProgress()
{
OnProgressAction(new JobProgressArgs { Sender = this });
}
public void Abort()
{
Store.Status = JobStatus.AbortRequested;
ChildreenJob.ForEach(c=>c.Abort());
}
public Job GetChild(string childId)
{
return GetChildreen().FirstOrDefault(child => child.Id == childId);
}
public void NotifyProgress(int progress)
{
OnProgressAction(new JobProgressArgs { Sender = this,Progress = progress});
}
public void StartBlocked()
{
var worker = new BackgroundWorkerEx();
worker.DoWork += (s, e) =>
{
Start();
Wait();
};
worker.RunWorkerBlocked();
}
public Job GetSibling(string id)
{
return Parent.GetChild(id);
}
public void Stop()
{
Store.StopRequested = true;
var stopWatch = new Stopwatch();
stopWatch.Start();
while (!IsComplete&&stopWatch.ElapsedMilliseconds<MaxWaitTimeToStop)
{
DoEvents();
}
}
private static void DoEvents()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
public void Pause()
{
Store.PauseRequested = true;
var stopWatch = new Stopwatch();
stopWatch.Start();
while (Store.Status!=JobStatus.Paused && stopWatch.ElapsedMilliseconds < MaxWaitTimeToStop)
{
DoEvents();
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.