I'm using System.Timers.Timer in my WPF application. I want to understand how Timer does behave, after Computer is hibernated, and sleep. I'm getting some weird issues with my application, after computer is getting resumed from hibernate.
How should I handle timers, and how do they behave when computer is in hibernate/sleep mode?
I have a midnight timer which should work each midnight to reset the default values on UI.
Here is the code that creates the timer:
private void ResetMidnightTimer() { // kill the old timer DisposeMidnightTimer(); _midnightTimer = new Timer(); // scheduling the timer to elapse 1 minute after midnight _midnightTimer.Interval = (DateTime.Today.AddDays(1).AddMinutes(1) - DateTime.Now).TotalMilliseconds; _midnightTimer.Elapsed += (_, __) => UpdateRecommendedCollectingTime(); _midnightTimer.Enabled = true; _midnightTimer.Start(); }
On UI page's contructor, I call the method which calls ResestMidnightTimer() and creates the timer de facto. After that the timer just waits for the night.
When the night time (actually it is the 12:01 AM) comes, the timer works, resets the default values as expected and then disposes existing timer. Finally it creates a new midnight timer for next day. But if I try to hibernate the computer during that day, the midnight timer won't work and won't reset the default values.
Is that because while hibernating it just postpones the event handling by the same amount of time it was hibernated?
Yes, they run in a different thread.
The application thread creates the timer, which waits one second and then executes the CheckStatus callback method every 250 milliseconds. The application thread then blocks until the AutoResetEvent object is signaled. When the CheckStatus callback method executes maxCount times, it calls the AutoResetEvent.
This depends on how you are using your timers. If you are using them to initiate some event that occurs infrequently (greater than a couple minutes) then you will probably see some 'weird' behavior. Since you don't specify what that 'weird' behavior is, I'm going to assume that your program's timer goes off later than it should.
Explanation: The problem with going to sleep/hibernating is that all programs are suspended. This means that your Timers are not being updated and thus when you sleep/hibernate and come back, it is as if you were frozen for that period of time that you were sleeping/hibernating. This means if you have a timer set to go off in an hour and your computer goes to sleep at the 15 minute mark, once it wakes up it will have another 45 minutes to go, regardless of how long the computer was sleeping.
Solution: One fix would be to keep a DateTime around of the last time the event occurred. Then, have a timer go off periodically (every 10 seconds or 10 minutes, depending on the precision desired) and check the DateTime of the last execution. If the difference between now and the last execution time is greater than or equal to the interval desired, THEN you run execution.
This will fix it so that if an event 'should have' occurred during sleeping/hibernating, it will start the moment you return from sleeping/hibernating.
Update: The solution presented above will work and I'll fill in a couple of details to help you implement it.
Instead of creating/disposing of new Timers, create ONE timer to use that is RECURRING (the AutoReset property is set to true)
The interval of the single timer should NOT be set according to the next time the event should occur. Instead, it should be set to a value you choose that will represent the polling frequency (how often it checks to see if the 'event' should run). The choice should be a balance of efficiency and precision. If you NEED it to run REALLY close to 12:01 AM then you set the interval to around 5-10 seconds. If it is less important that it be at exactly 12:01 AM, you can increase the interval to something like 1-10 minutes.
You need to keep around a DateTime of when the last execution occurred OR when the next execution should happen. I would prefer 'when the next execution should happen' so that you aren't doing (LastExecutionTime + EventInterval) each time the timer elapses, you'll just be comparing the current time and the time the event should occur.
Once the timer elapses and the event SHOULD occur (somewhere around 12:01 AM), you should update the stored DateTime and then run the code you want run at 12:01 AM.
Sleep vs. Hibernate Clarification: The main difference between sleep and hibernate is that in sleep, everything is kept in RAM whereas hibernate saves the current state to disk. The main advantage of hibernate is that the RAM no longer needs power and thus expends less energy. This is why it is recommended to use hibernate over sleep when dealing with laptops or other devices using a finite amount of energy.
That said, there is no difference in the execution of programs as they are being suspended in either case. Unfortunately, the System.Timers.Timer does not 'wake up' a computer and so you can't enforce your code to be run at ~12:01 AM.
I believe there are OTHER ways to 'wake up' a computer but unless you go that route the best you can do is run your 'event' during the next 'polling event' of your timer after it comes out of sleep/hibernate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With