Introduction
Occasionally, I find I have a need for asynchronous events to be queued and fired at a regular interval. The actual application in this case was asking a vehicle tracking system for a location fix every 15 seconds, for various vehicles, plus occasional polling of battery state. Previously, I had used the STL PriorityQueue
to do a similar thing in C++ for a nuclear reprocessing plant monitoring system, where various sensors had to be polled at different intervals.
Background
I have used BenDi's PriorityQueue code which is, I have to say, superb! My Q
class derives from his base BinaryPriorityQueue
.
Using the code
There's a console app that shows how to use the code - obviously it's a bit naive and you would probably want to poll the queue using a worker thread, or even embed the thread in the Q
object and have it raise a .NET type event when necessary.
To use the event queue, do this:
- Build an event queue object:
EventQueue q = new EventQueue();
- Build some events to go in it...
RepeatEvent reFive =
new RepeatEvent(DateTime.Now.AddSeconds(10), 5, 5, null);
RepeatEvent reUnlimted =
new RepeatEvent(DateTime.Now.AddSeconds(5), -1, 20, null);
OneShotEvent oneShot = new OneShotEvent(DateTime.Now.AddSeconds(12), null);
- Push them onto the queue.
q.Push(reFive);
q.Push(reUnlimted);
q.Push(oneShot);
- And run this code in a loop or a thread to access the events:
while (q.Count != 0)
{
QueuedEvent qe = q.GetNextReadyEvent();
if (qe != null)
{
if (qe.Payload != null)
{
}
if (qe.ReQueue())
{
q.Push(qe);
}
}
Thread.Sleep(10);
}
Under the Hood
EventQueue
derives from BinaryPriorityQueue
:
public class EventQueue : BinaryPriorityQueue
Constructor calls the base constructor passing in the comparer:
public EventQueue() : base(new EventQueueComparer())
Pop
and Peek
are overloaded to cast result to QueuedEvent
type:
public new QueuedEvent Pop()
public new QueuedEvent Peek()
GetNextReadyEvent
has a look using Peek
, and if the event has fired, hauls it off:
public QueuedEvent GetNextReadyEvent()
{
QueuedEvent e = Peek();
if (e != null && e.IsFired())
return base.Pop() as QueuedEvent;
else
return null;
}
Abstract QueuedEvent
class is the base class that all elements of the queue derive from:
public abstract class QueuedEvent
All queued objects therefore have an 'IsFired
' function:
public bool IsFired()
{
return (dtNextFiringTime < DateTime.Now);
}
RepeatEvent
object derives from the abstract base and takes a quantity and an interval as parameters:
public RepeatEvent(DateTime dt, int qty,
int interval, object payload) : base(dt, payload)
And in its re-queue function, it works out the next firing time and decrements the number of shots:
public override bool ReQueue()
{
if (iNumberOfShots != -1)
iNumberOfShots--;
dtNextFiringTime = dtNextFiringTime.AddSeconds(iInterval);
return (iNumberOfShots != 0);
}
The comparer class speaks for itself, simply checks the NextFiringTime
of two events:
public class EventQueueComparer : IComparer
{
public int Compare(object x, object y)
{
QueuedEvent xx = x as QueuedEvent;
QueuedEvent yy = y as QueuedEvent;
return xx.NextFiringTime.CompareTo(yy.NextFiringTime);
}
}
I think that about covers it. Nice and simple - enjoy! :o)
History
1.0 - Original posting.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.