Multithreaded Timers
System.Threading.Timer is the simplest multithreaded timer: it has just a constructor and two methods. In the following example, a timer calls the Tick method, which writes “tick…” after five seconds have elapsed, and then every second after that, until the user presses Enter:
Example
using System; using System.Threading; namespace ConsoleApplication1 { class Program { static void Main() { // First interval = 5000ms; subsequent intervals = 1000ms Timer tmr = new Timer(Tick, "tick...", 5000, 1000); Console.ReadLine(); tmr.Dispose(); // This both stops the timer and cleans up. } static void Tick(object data) { // This runs on a pooled thread Console.WriteLine(data); // Writes "tick..." } } }
You can change a timer’s interval later by calling its Change method. If you want a timer to fire just once, specify Timeout.Infinite in the constructor’s last argument. The .NET Framework provides another timer class of the same name in the System.Timers namespace. This simply wraps the System.Threading.Timer, providing additional convenience while using the identical underlying engine. Here’s a summary of its added features:
- A Component implementation, allowing it to be sited in Visual Studio’s designer.
- An Interval property instead of a Change method
- An Elapsed event instead of a callback delegate
- An Enabled property to start and stop the timer (its default value being false)
- Start and Stop methods in case you’re confused by Enabled
- An AutoReset flag for indicating a recurring event (default value is true)
- A SynchronizingObject property with Invoke and BeginInvoke methods for
safely calling methods on WPF elements and Windows Forms controls.
Example
using System; using System.Timers; namespace ConsoleApplication1 { class Program { static void Main() { Timer tmr = new Timer(); // Doesn't require any args tmr.Interval = 500; tmr.Elapsed += tmr_Elapsed; // Uses an event instead of a delegate tmr.Start(); // Start the timer Console.ReadLine(); tmr.Stop(); // Stop the timer Console.ReadLine(); tmr.Start(); // Restart the timer Console.ReadLine(); tmr.Dispose(); // Permanently stop the timer } static void tmr_Elapsed(object sender, EventArgs e) { Console.WriteLine("Tick"); } } }
Multithreaded timers use the thread pool to allow a few threads to serve many timers. This means that the callback method or Tick event may fire on a different thread each time it is called. Furthermore, a Tick always fires (approximately) on time— regardless of whether the previous Tick has finished executing. Hence, callbacks or event handlers must be thread-safe.