0

I'm writing a basic simulation in C# and conceptually it is simplest to design it as multiple timers firing events at various intervals ranging from around half a second to multiple seconds. I've done a rough draft using System.Timers.Timer and it works well enough.

However, it's just a simulation so I don't want to wait! Is there a way to instantly trigger whichever Timer would fire next?

Or maybe this is the wrong approach, and I should do something manual (iterating over a Dictionary of delays) as explained here? Is there a better pattern for a simulation like this?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Nick P
  • 759
  • 5
  • 20
  • 2
    Sure, don't use a timer. Seriously, the body of your timer handlers should do nothing but call another method that **you** can call whenever you want. e.g. `OnTimer1() { DoSomething1() }`. If you want to call it immediately just directly call `DoSomething1()` –  Nov 08 '18 at 06:08

1 Answers1

2

One way to approach this is to use a SortedList of pending events (sorted on their "due date") and to use a timer that's firing frequently enough to satisfy the sort of time intervals that you're wanting to work with (e.g. once every 250ms may be enough here).

Each time the (single) timer fires, it keeps examining the front of the list, and if the item at the front has a due date in the past, then we dequeue the item and arrange for it to run (whether you run the events on the timer thread itself or e.g. start new Tasks to execute them depends to an extent on whether events need to happen in parallel and how long event processing takes).

Normally, each event object will have some kind of Action embedded in its structure so that this dispatching code can be quite straightforward. Recurring events may enqueue their "next" execution as part of their own actions, or you may choose to make that another form of action taken by the timer thread. (This second model tends to work better if you're doing parallel executions, since it's only the timer thread that interacts with the event queue and so no locking is required).

Finally, how do you run things more frequently? Ditch the timer entirely and just dequeue items from the queue continuously, ignoring their due dates.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • I guess the point of my question was that generating the sequence is the annoying part since some events will fire a few times before others fire once. Having the Timer handle the ordering will let me be more declarative and save me from writing my own logic to generate the events in a sorted list - which I can definitely do, I'd just rather not reinvent that part. I also assumed that there would be a mocking technique available to help testing Timer interactions, generating the sequence without a real world delay but in the correct order. – Nick P Nov 08 '18 at 08:45
  • @NickP - as I alluded to in the third para, you end up with the core loop being something along the lines of `dequeue front event. Grab Action. If it's a recurring event, add the interval to the due date and enqueue. Run the action`. If the enqueue ends up putting this event back at the front of the queue, so be it. I'm not seeing the complexity there. – Damien_The_Unbeliever Nov 08 '18 at 08:48
  • I think I glossed over that part the first time - it definitely sounds like a simple enough solution, and the idea of the Timer allows for real-time delays if I still need it. I'll give it a short. – Nick P Nov 08 '18 at 09:01
  • @Damien_The_Unbeliever I'm not a C# programmer, so pardon my ignorance here. Does `SortedList` fully order the data? If so, a priority queue implementation would be better for scalability. Priority queues are the standard approach used in discrete event simulation modeling since the focus is always on what's the *next* event that will occur, i.e., the event with the smallest time of occurrence. You don't need a full ordering property on later events. – pjs Nov 08 '18 at 14:50
  • @pjs - there's no more specific priority queue collection in .NET that I'm aware of. The `SortedX` collections are the closest. That's why I picked `SortedList`. – Damien_The_Unbeliever Nov 08 '18 at 17:45
  • @Damien_The_Unbeliever That's a shame. Too many standard libraries have significant gaps such as this one. – pjs Nov 08 '18 at 18:10