System.Timers.Timer/Threading.Timer vs Thread with WhileLoop + Thread.Sleep For Periodic Tasks
Asked Answered
F

4

44

In my application I have to send periodic heartbeats to a "brother" application.

Is this better accomplished with System.Timers.Timer/Threading.Timer or Using a Thread with a while loop and a Thread.Sleep?

The heartbeat interval is 1 second.

while(!exit)
{
   //do work
   Thread.Sleep(1000);
}

or

myTimer.Start( () => { 
                       //do work 
                      }, 1000); //pseudo code (not actual syntax)...
Flashcube answered 12/5, 2010 at 20:16 Comment(0)
L
32

System.Threading.Timer has my vote.

System.Timers.Timer is meant for use in server-based (your code is running as a server/service on a host machine rather than being run by a user) timer functionality.

A Thread with a While loop and Thread.Sleep command is truly a bad idea given the existance of more robust Timer mecahnisms in .NET.

Lopsided answered 12/5, 2010 at 20:17 Comment(2)
The System.Timers.Timer class really can be used in a user mode application just as easily as System.Threading.Timer. Internally, System.Timers.Timer uses System.Threading.Timer for it's internal timing mechanism, and only wraps it up to handle design time issues...Thermoluminescence
BEWARE the timer raises it's tick event on any thread pool thread so you would have to handle re-entry and thread safety! My vote goes to wait handel which use OS signals so achieve higher timing accuracy and everything executes inside your thread.Lapith
R
23

Server Timers are a different creature than sleeping threads.

For one thing, based on the priority of your thread, and what else is running, your sleeping thread may or may not be awoken and scheduled to run at the interval you ask. If the interval is long enough, and the precision of scheduling doesn't really matter, Thread.Sleep() is a reasonable choice.

Timers, on the other hand, can raise their events on any thread, allowing for better scheduling capabilities. The cost of using timers, however, is a little bit more complexity in your code - and the fact that you may not be able to control which thread runs the logic that the timer event fires on. From the docs:

The server-based Timer is designed for use with worker threads in a multithreaded environment. Server timers can move among threads to handle the raised Elapsed event, resulting in more accuracy than Windows timers in raising the event on time.

Another consideration is that timers invoke their Elapsed delegate on a ThreadPool thread. Depending on how time-consuming and/or complicated your logic is, you may not want to run it on the thread pool - you may want a dedicated thread. Another factor with timers, is that if the processing takes long enough, the timer event may be raised again (concurrently) on another thread - which can be a problem if the code being run is not intended or structured for concurrency.

Don't confuse Server Timers with "Windows Timers". The later usually refers to a WM_TIMER messages tha can be delivered to a window, allowing an app to schedule and respond to timed-processing on its main thread without sleeping. However, Windows Timers can also refer to the Win API for low-level timing (which is not the same as WM_TIMER).

Rawdan answered 12/5, 2010 at 20:18 Comment(4)
Thanks for the answer. I'm a little confused between "Server Timers" and "Windows Timers" and how that relates to System.Threading.Timer and Thread.SleepFlashcube
Okay, System.Timers.Timer is a server timer. Gotcha!Flashcube
In general it is a bad idea to waste a full thread that will mostly be sleeping. Threads are heavyweight and it is best to use one of the ThreadPool-based alternatives.Revivify
@MarkSowul Light-work threads are relatively lightweight (eg. not "heavyweight monsters") with reasonable usages (10k connections on separate threads != reasonable usage..) While threads do take up memory and scheduling, modern .NET/windows versions greatly address the memory issue (ie. control for smaller stacks and eager allocation; might not have been so in 2012) and a "long" Thread.Sleep is relatively cheap in terms of amortized scheduling costs.Saidel
B
21

Neither :)

Sleeping is typically frowned upon (unfortunately I cannot remember the particulars, but for one, it is an uninteruptible "block"), and Timers come with a lot of baggage. If possible, I would recommend System.Threading.AutoResetEvent as such

// initially set to a "non-signaled" state, ie will block
// if inspected
private readonly AutoResetEvent _isStopping = new AutoResetEvent (false);

public void Process()
{
    TimeSpan waitInterval = TimeSpan.FromMilliseconds (1000);

    // will block for 'waitInterval', unless another thread,
    // say a thread requesting termination, wakes you up. if
    // no one signals you, WaitOne returns false, otherwise
    // if someone signals WaitOne returns true
    for (; !_isStopping.WaitOne (waitInterval); )
    {
        // do your thang!
    }
}

Using an AutoResetEvent (or its cousin ManualResetEvent) guarantees a true block with thread safe signalling (for such things as graceful termination above). At worst, it is a better alternative to Sleep

Hope this helps :)

Bohaty answered 12/5, 2010 at 20:27 Comment(3)
I like it, the ability to cleanly shutdown your thread is nice.Goolsby
Why a for loop rather than while?Paulino
@gav, while works just as well, for is a stylistic preference.Bohaty
L
1

I've found that the only timer implementation that actually scales is System.Threading.Timer. All the other implementations seem pretty bogus if you're dealing with a non trivial number of scheduled items.

Lesleylesli answered 12/5, 2010 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.