views:

607

answers:

6

Suppose I have a non-recurring event that needs to be raised X seconds from now such as a timeout. Intuitively it would make sense to create a System.Timers.Timer, set its interval to X*1000, wire its tick up to the event and start it. Since this is a non-recurring event and you only want it raised once you would then have to stop the timer after it ticks.

The fact that Timers are inherently recurring however makes me distrustful if this is indeed the best way of doing it. Would it be better/more accurate/safer to save the time started, set the timer to tick every second (or even millisecond) and on tick poll the system for time and manually raise the target event only once the requisite time has elapsed?

Can anyone weigh in on which if either method is best (perhaps there is another option I didn't think of too). Does one method become better than the other if the timespan that I need to wait is measured in milliseconds?

+5  A: 

just use a normal timer and disable it after it has elapsed once. that should solve your problem.

both, system.threading.timer and system.timers.timer support this.

Joachim Kerschbaumer
I've already mulled this option but I'm curious about reliability and such
George Mauer
+1  A: 

Spin off a new BackgroundWorker, sleep, close.

var worker = new BackgroundWorker();
worker.DoWork += delegate {
  Thread.Sleep(30000); 
  DoStuff();
} 
worker.RunWorkerAsync();
Unsliced
thats an interesting solution...
George Mauer
This will occupy a processor for 30000 ms, isn't it?
Nenad
@Nency - no I don't think so, the background thread should be asleep and so not use any CPU time.
RickL
Exactly - the Async will mean it will sleep on a new Thread, so no more CPU consumption than a Timer on its own thread.
Unsliced
A: 

just set it to tick after X seconds, and in the code of the tick, do:

timer.enabled = false;

worked for me.

Nic Wise
+9  A: 

This constructor for the System.Threading.Timer allows you to specify a period. If you set this parameter to -1, it will disable periodic signaling and only execute once.

public Timer(
    TimerCallback callback,
    Object state,
    TimeSpan dueTime,
    TimeSpan period
)
Ben Hoffstein
!!! holy crap ben, never knew that, do you you have all of msdn memorized or something
George Mauer
Didn't know that either. I always found Qt's QTimer::singleshot easier, but good to know that the BCL Timer can do this :)
OregonGhost
Yes, I read it every night before bed :-)
Ben Hoffstein
As a question: just calling Timer(callback, state, dueTime, period).Start() may result in the timer being GC'd, so I still have to keep the Timer object?
OregonGhost
@OregonGhost, presumably you mean "(new Timer(...)).Start()". You shouldn't do that; Timer is IDisposable.
dangph
A: 

If you want an accurate time measure, you should consider doubling the timer frequency and using DateTime.Now to compare with your start time. Timers and Thread.Sleep aren't necessarily exact in their time measurements.

Jeff Yates
+1  A: 

You can use a System.Timers.Timer with AutoReset = true, or a System.Threading.Timer with an infinite period (System.Threading.Timeout.Infinite = -1) to execute a timer once.

In either case, you should Dispose your timer when you've finished with it (in the event handler for a Timers.Timer or the callback for a Threading.Timer) if you don't have a recurring interval.

Joe