|
using System;
using System.Collections.Generic;
using System.Threading;
namespace TrafficCalming
{
/// <summary>
/// Calms the traffic produced by rapiddly repeating events.
/// </summary>
/// <remarks>
/// When handling some repeating events it might be necesary to slow down traffic, for instance to
/// show progress in the UI. This service executes events pausing after each execution, new events
/// arrived are discarded. It will kind of work like a limited (very) capacity queue.
///
/// The name comes from "Traffic calming" (http://en.wikipedia.org/wiki/Traffic_calming).
///
/// Is important to see this objects should not be shared among objects as they will receive
/// notifications from the other objects as well as their own.
/// </remarks>
public class EventCalmer
{
private enum CalmerState
{
Idle,
Executing,
ExecutingOneInQueue,
Waiting,
WaitingOneInQueue,
};
private static readonly Dictionary<CalmerState, CalmerState> EventReceivedTransitions =
new Dictionary<CalmerState, CalmerState>
{
{ CalmerState.Idle, CalmerState.Executing },
{ CalmerState.Executing, CalmerState.ExecutingOneInQueue },
{ CalmerState.Waiting, CalmerState.WaitingOneInQueue },
{ CalmerState.WaitingOneInQueue, CalmerState.WaitingOneInQueue },
{ CalmerState.ExecutingOneInQueue, CalmerState.ExecutingOneInQueue },
};
private static readonly Dictionary<CalmerState, CalmerState> DoneOrFinishedTransitions =
new Dictionary<CalmerState, CalmerState>
{
{ CalmerState.Executing, CalmerState.Waiting },
{ CalmerState.Waiting, CalmerState.Idle },
{ CalmerState.ExecutingOneInQueue, CalmerState.WaitingOneInQueue },
{ CalmerState.WaitingOneInQueue, CalmerState.Executing },
};
private readonly object _criticalSectionDoor = new object();
private readonly TimeSpan _sleepTime;
private DateTime _lastExecutionBeganAt;
private CalmerState _currentState;
/// <summary>
/// Creates an instance
/// </summary>
/// <param name="sleepTime">Pause time between executions</param>
public EventCalmer(TimeSpan sleepTime)
{
_sleepTime = sleepTime;
}
/// <summary>
/// Creates an instance
/// </summary>
/// <param name="sleepTime">Pause time between executions</param>
public EventCalmer(int sleepTime)
: this(TimeSpan.FromMilliseconds(sleepTime))
{
}
/// <summary>
/// Notifies an event has occurred
/// </summary>
public event EventHandler EventOccurred;
private void OnEventOccurred(EventArgs e)
{
_lastExecutionBeganAt = DateTime.Now;
if (EventOccurred != null) EventOccurred(this, e);
}
/// <summary>
/// HandleEvent to subscribe to the actual event producer.
/// </summary>
/// <param name="sender">Event producer</param>
/// <param name="e">Event args</param>
public void HandleEvent(object sender, EventArgs e)
{
EventReceived();
}
private void EventReceived()
{
lock (_criticalSectionDoor)
{
var newState = GetStateToMoveToWhenEventArrives();
SetCurrentStateTo(newState);
if (_currentState == CalmerState.Executing)
BeginExecutionThread();
}
}
private CalmerState GetStateToMoveToWhenEventArrives()
{
return EventReceivedTransitions[_currentState] ;
}
private void SetCurrentStateTo(CalmerState newState)
{
_currentState = newState;
}
private void BeginExecutionThread()
{
Action executionThread = ExecuteWhileNotIddle;
executionThread.BeginInvoke(null, null);
}
private void ExecuteWhileNotIddle()
{
while (_currentState != CalmerState.Idle)
{
if (_currentState == CalmerState.Executing ||
_currentState == CalmerState.ExecutingOneInQueue)
DoExecuteStep();
else
DoWaitStep();
UpdateStateAfterDoneOrFinished();
}
}
private void DoExecuteStep()
{
OnEventOccurred(EventArgs.Empty);
}
private void DoWaitStep()
{
var stillNeedToWait = _sleepTime - GetTimeItTookLastExecution();
if (stillNeedToWait > TimeSpan.Zero)
Thread.Sleep(stillNeedToWait);
}
private TimeSpan GetTimeItTookLastExecution()
{
return DateTime.Now - _lastExecutionBeganAt;
}
private void UpdateStateAfterDoneOrFinished()
{
lock (_criticalSectionDoor)
{
var newState = GetStateToMoveToWhenDoneOrFinished();
SetCurrentStateTo(newState);
}
}
private CalmerState GetStateToMoveToWhenDoneOrFinished()
{
return DoneOrFinishedTransitions[_currentState];
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I Received a Bachelor's Degree in Computer Science at the Mathematics and Computer Science Faculty, University of Havana, Cuba.
I mainly work in web applications using C# and some Javascript. Some very few times do some Java.