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() { } } }