ln.threading/ln.threading/PoolJob.cs

173 lines
4.5 KiB
C#

using System;
using ln.logging;
using System.Threading;
namespace ln.threading
{
public delegate void JobDelegate();
public delegate void ExtendedJobDelegate(PoolJob poolJob);
public enum PoolJobState { PREPARED, RUNNING, DONE, FAILED };
public class PoolJob
{
public string Name { get; set; }
public JobDelegate Job { get; }
public ExtendedJobDelegate ExtendedJob { get; }
public double Progress { get; set; }
public string State { get; set; }
public PoolJobState JobState { get; private set; }
public bool JobAbortRequested { get; private set; }
private Pool Pool { get; set; }
protected PoolJob()
{
JobState = PoolJobState.PREPARED;
}
public PoolJob(JobDelegate job)
: this()
{
Job = job;
ExtendedJob = null;
Name = "N/A";
}
public PoolJob(ExtendedJobDelegate job)
: this()
{
Job = null;
ExtendedJob = job;
Name = "N/A";
}
public PoolJob(String name, ExtendedJobDelegate job)
: this()
{
Job = null;
ExtendedJob = job;
Name = name;
}
public void RequestAbort()
{
JobAbortRequested = true;
if (Pool != null)
{
PoolThread poolThread = Pool.FindPoolThread(this);
if (poolThread != null)
{
if (poolThread.Thread.ThreadState == ThreadState.WaitSleepJoin)
poolThread.Thread.Interrupt();
}
}
}
public void ForceFail()
{
JobState = PoolJobState.FAILED;
}
public void setState(string state,params object[] p)
{
State = String.Format(state, p);
}
public virtual void RunJob()
{
if (Job != null)
{
Job();
}
else if (ExtendedJob != null)
{
ExtendedJob(this);
}
else
{
Logging.Log(LogLevel.ERROR, "PoolJob without JobDelegate tried to run");
JobState = PoolJobState.FAILED;
}
}
public void Run(Pool pool)
{
Pool = pool;
try
{
JobState = PoolJobState.RUNNING;
RunJob();
JobState = PoolJobState.DONE;
if (Pool.DEBUG && (State != null) && !String.Empty.Equals(State))
Logging.Log(LogLevel.DEBUG, "PoolJob exited normally with State={0}", State);
}
catch (Exception e)
{
JobState = PoolJobState.FAILED;
Logging.Log(LogLevel.ERROR, "PoolJob: {0} caught exception {1}", this, e);
Logging.Log(e);
}
Pool = null;
}
public void SplitJob(PoolJob[] jobs)
{
if (Pool == null)
throw new ArgumentNullException();
foreach (PoolJob job in jobs)
{
if (!Pool.Enqueue(job))
{
Logging.Log(LogLevel.ERROR, "PoolJob.SplitJob(): Failed to enqueue splitted Job");
foreach (PoolJob _job in jobs)
{
_job.RequestAbort();
}
throw new Exception("Failed to enqueue splitted Job");
}
}
while (true)
{
int nFinished = 0, nError = 0;
double progress = 0.0;
foreach (PoolJob job in jobs)
{
progress += job.Progress;
switch (job.JobState)
{
case PoolJobState.DONE:
nFinished++;
break;
case PoolJobState.FAILED:
nError++;
break;
}
if (JobAbortRequested)
job.RequestAbort();
}
Progress = progress / jobs.Length;
if ((nError + nFinished) == jobs.Length)
break;
Thread.Sleep(1000);
}
}
public virtual void Prepare()
{
}
}
}