155 lines
4.8 KiB
C#
155 lines
4.8 KiB
C#
// /**
|
|
// * File: SchedulingPool.cs
|
|
// * Author: haraldwolff
|
|
// *
|
|
// * This file and it's content is copyrighted by the Author and / or copyright holder.
|
|
// * Any use wihtout proper permission is illegal and may lead to legal actions.
|
|
// *
|
|
// *
|
|
// **/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using ln.types.btree;
|
|
using ln.logging;
|
|
namespace ln.types.threads
|
|
{
|
|
|
|
public class SchedulingPool
|
|
{
|
|
static SchedulingPool defaultPool = null;
|
|
static public SchedulingPool Default
|
|
{
|
|
get
|
|
{
|
|
if (defaultPool == null)
|
|
defaultPool = new SchedulingPool();
|
|
|
|
return defaultPool;
|
|
}
|
|
set => defaultPool = value;
|
|
}
|
|
|
|
public Pool ThreadPool { get; private set; }
|
|
public int ThreadCount => ThreadPool.PoolSize;
|
|
|
|
BTreeValueList<double, ScheduledJob> schedule = new BTreeValueList<double, ScheduledJob>();
|
|
Thread schedulerThread;
|
|
|
|
Dictionary<Action, ScheduledJob> scheduledJobs = new Dictionary<Action, ScheduledJob>();
|
|
|
|
public SchedulingPool()
|
|
:this(Environment.ProcessorCount)
|
|
{
|
|
}
|
|
public SchedulingPool(int nThreads)
|
|
{
|
|
ThreadPool = new Pool(nThreads);
|
|
ThreadPool.Start();
|
|
|
|
schedulerThread = new Thread(scheduler);
|
|
schedulerThread.Start();
|
|
}
|
|
|
|
void scheduler()
|
|
{
|
|
while (true)
|
|
{
|
|
lock (this)
|
|
{
|
|
double now = DateTime.Now.ToUnixTimeMilliseconds();
|
|
if (schedule.Empty)
|
|
{
|
|
Monitor.Wait(this);
|
|
}
|
|
else if (schedule.First <= now)
|
|
{
|
|
while (!schedule.Empty && (schedule.First <= now))
|
|
{
|
|
ScheduledJob scheduledJob = schedule.Shift();
|
|
ThreadPool.Enqueue(scheduledJob);
|
|
scheduledJob.Reschedule();
|
|
enqueue(scheduledJob);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Monitor.Wait(this, (int)(schedule.First - now));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void enqueue(ScheduledJob job)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (schedule.TryAdd(job.NextScheduledExecution, job))
|
|
Monitor.Pulse(this);
|
|
}
|
|
}
|
|
void dequeue(ScheduledJob job)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (schedule.TryRemove(job.NextScheduledExecution, job))
|
|
Monitor.Pulse(this);
|
|
}
|
|
}
|
|
|
|
public void Schedule(Action action, double scheduledIntervall)
|
|
{
|
|
if (!scheduledJobs.TryGetValue(action, out ScheduledJob scheduledJob))
|
|
{
|
|
scheduledJob = new ScheduledJob(action, scheduledIntervall);
|
|
scheduledJobs.Add(action, scheduledJob);
|
|
}
|
|
else
|
|
{
|
|
scheduledJob.ScheduledInterval = scheduledIntervall;
|
|
}
|
|
enqueue(scheduledJob);
|
|
}
|
|
public void Unschedule(Action action)
|
|
{
|
|
if (scheduledJobs.TryGetValue(action, out ScheduledJob scheduledJob))
|
|
{
|
|
dequeue(scheduledJob);
|
|
}
|
|
}
|
|
|
|
public class ScheduledJob : PoolJob
|
|
{
|
|
public SchedulingPool Pool { get; private set; }
|
|
public Action Action { get; }
|
|
|
|
public double NextScheduledExecution { get; set; }
|
|
public double ScheduledInterval { get; set; }
|
|
|
|
public ScheduledJob(Action action)
|
|
: this(action, 0, DateTime.Now.ToUnixTimeMilliseconds())
|
|
{ }
|
|
public ScheduledJob(Action action, double scheduledInterval)
|
|
: this(action, scheduledInterval, DateTime.Now.ToUnixTimeMilliseconds() + scheduledInterval)
|
|
{
|
|
}
|
|
public ScheduledJob(Action action, double scheduledInterval, double nextScheduledExecution)
|
|
{
|
|
Action = action;
|
|
ScheduledInterval = scheduledInterval;
|
|
NextScheduledExecution = nextScheduledExecution;
|
|
}
|
|
|
|
public override void RunJob() => Action.Invoke();
|
|
|
|
public void Reschedule() => Reschedule(ScheduledInterval);
|
|
public void Reschedule(double interval)
|
|
{
|
|
double currentTime = DateTime.Now.ToUnixTimeMilliseconds();
|
|
while (NextScheduledExecution < currentTime)
|
|
NextScheduledExecution += ScheduledInterval;
|
|
}
|
|
}
|
|
}
|
|
}
|