| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- using System;
- using System.Threading;
- using Abp.Dependency;
- namespace Abp.Threading.Timers
- {
- /// <summary>
- /// A roboust timer implementation that ensures no overlapping occurs. It waits exactly specified <see cref="Period"/> between ticks.
- /// </summary>
- //TODO: Extract interface or make all members virtual to make testing easier.
- public class AbpTimer : RunnableBase, ITransientDependency
- {
- /// <summary>
- /// This event is raised periodically according to Period of Timer.
- /// </summary>
- public event EventHandler Elapsed;
- /// <summary>
- /// Task period of timer (as milliseconds).
- /// </summary>
- public int Period { get; set; }
- /// <summary>
- /// Indicates whether timer raises Elapsed event on Start method of Timer for once.
- /// Default: False.
- /// </summary>
- public bool RunOnStart { get; set; }
- /// <summary>
- /// This timer is used to perfom the task at spesified intervals.
- /// </summary>
- private readonly Timer _taskTimer;
- /// <summary>
- /// Indicates that whether timer is running or stopped.
- /// </summary>
- private volatile bool _running;
- /// <summary>
- /// Indicates that whether performing the task or _taskTimer is in sleep mode.
- /// This field is used to wait executing tasks when stopping Timer.
- /// </summary>
- private volatile bool _performingTasks;
- /// <summary>
- /// Creates a new Timer.
- /// </summary>
- public AbpTimer()
- {
- _taskTimer = new Timer(TimerCallBack, null, Timeout.Infinite, Timeout.Infinite);
- }
- /// <summary>
- /// Creates a new Timer.
- /// </summary>
- /// <param name="period">Task period of timer (as milliseconds)</param>
- /// <param name="runOnStart">Indicates whether timer raises Elapsed event on Start method of Timer for once</param>
- public AbpTimer(int period, bool runOnStart = false)
- : this()
- {
- Period = period;
- RunOnStart = runOnStart;
- }
- /// <summary>
- /// Starts the timer.
- /// </summary>
- public override void Start()
- {
- if (Period <= 0)
- {
- throw new AbpException("Period should be set before starting the timer!");
- }
- base.Start();
- _running = true;
- _taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite);
- }
- /// <summary>
- /// Stops the timer.
- /// </summary>
- public override void Stop()
- {
- lock (_taskTimer)
- {
- _running = false;
- _taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
- }
- base.Stop();
- }
- /// <summary>
- /// Waits the service to stop.
- /// </summary>
- public override void WaitToStop()
- {
- lock (_taskTimer)
- {
- while (_performingTasks)
- {
- Monitor.Wait(_taskTimer);
- }
- }
- base.WaitToStop();
- }
- /// <summary>
- /// This method is called by _taskTimer.
- /// </summary>
- /// <param name="state">Not used argument</param>
- private void TimerCallBack(object state)
- {
- lock (_taskTimer)
- {
- if (!_running || _performingTasks)
- {
- return;
- }
- _taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
- _performingTasks = true;
- }
- try
- {
- if (Elapsed != null)
- {
- Elapsed(this, new EventArgs());
- }
- }
- catch
- {
- }
- finally
- {
- lock (_taskTimer)
- {
- _performingTasks = false;
- if (_running)
- {
- _taskTimer.Change(Period, Timeout.Infinite);
- }
- Monitor.Pulse(_taskTimer);
- }
- }
- }
- }
- }
|