I am trying to create a function that takes in an Action and a Timeout, and executes the Action after the Timeout. The function is to be non-blocking. The function must be
There is nothing built-in to .Net 4 to do this nicely. Thread.Sleep or even AutoResetEvent.WaitOne(timeout) are not good - they will tie up thread pool resources, I have been burned trying this!
The lightest weight solution is to use a timer - particularly if you will have many tasks to throw at it.
First make a simple scheduled task class:
class ScheduledTask
{
internal readonly Action Action;
internal System.Timers.Timer Timer;
internal EventHandler TaskComplete;
public ScheduledTask(Action action, int timeoutMs)
{
Action = action;
Timer = new System.Timers.Timer() { Interval = timeoutMs };
Timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Timer.Stop();
Timer.Elapsed -= TimerElapsed;
Timer = null;
Action();
TaskComplete(this, EventArgs.Empty);
}
}
Then, create a scheduler class - again, very simple:
class Scheduler
{
private readonly ConcurrentDictionary _scheduledTasks = new ConcurrentDictionary();
public void Execute(Action action, int timeoutMs)
{
var task = new ScheduledTask(action, timeoutMs);
task.TaskComplete += RemoveTask;
_scheduledTasks.TryAdd(action, task);
task.Timer.Start();
}
private void RemoveTask(object sender, EventArgs e)
{
var task = (ScheduledTask) sender;
task.TaskComplete -= RemoveTask;
ScheduledTask deleted;
_scheduledTasks.TryRemove(task.Action, out deleted);
}
}
It can be called as follows - and is very lightweight:
var scheduler = new Scheduler();
scheduler.Execute(() => MessageBox.Show("hi1"), 1000);
scheduler.Execute(() => MessageBox.Show("hi2"), 2000);
scheduler.Execute(() => MessageBox.Show("hi3"), 3000);
scheduler.Execute(() => MessageBox.Show("hi4"), 4000);