using System; using System.Threading; namespace ln.threading { public delegate void ElapsedDelegate(PoolTimer timer); public class PoolTimer : IDisposable { public event ElapsedDelegate Elapsed; TimeSpan interval; public TimeSpan Interval { get => interval; set { if (value <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(value)); interval = value; lock (this){ Monitor.Pulse(this); } } } DateTime nextStart; public DateTime NextStart => nextStart; bool canceled = true; public bool IsActive { get => !canceled; private set { lock (this) { if (value && canceled) Start(); else if (!value && !canceled) Stop(); } } } public PoolTimer(TimeSpan interval) { Interval = interval; } public PoolTimer(double interval) { Interval = TimeSpan.FromSeconds(interval); } public PoolTimer(int interval) { Interval = TimeSpan.FromMilliseconds(interval); } public PoolTimer(TimeSpan interval, Action action) :this(action) { Interval = interval; } public PoolTimer(double interval, Action action) :this(action) { Interval = TimeSpan.FromSeconds(interval); } public PoolTimer(int interval, Action action) :this(action) { Interval = TimeSpan.FromMilliseconds(interval); } PoolTimer(Action action) { Elapsed += (t)=>action(); } public void Start() { lock (this) { if (canceled){ canceled = false; DynamicThreadPool.DefaultPool.Enqueue(TimerThread); } } } public void Stop() { lock (this) { if (!canceled) { canceled = true; Monitor.Pulse(this); } } } void TimerThread() { lock (this) { nextStart = DateTime.Now + Interval; DateTime now; while (!canceled) { now = DateTime.Now; if ((nextStart < now) || (!Monitor.Wait(this, nextStart - now) && !canceled)) { DynamicThreadPool.DefaultPool.Enqueue(()=>Elapsed?.Invoke(this)); nextStart += Interval; } else { nextStart = DateTime.Now + Interval; } } } } public void Dispose() { Stop(); } } }