65.9K
CodeProject is changing. Read more.
Home

Use PriorityQueue to fire timed repeatable events

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (4 votes)

Apr 26, 2005

2 min read

viewsIcon

31460

downloadIcon

397

An article on using PriorityQueue to generate events for doing repeat actions, one off alarms, etc.

eventqueue.gif

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) 
            { 
                // do something.... 
            }
            // and, re queue if neccesary 
            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.