How System.Timers.Timer behave in WPF application, after Hibernate, and Sleep? - c#

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?

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.

Is that because while hibernating it just postpones the event handling by the same amount of time it was hibernated?
While the computer is in a suspended mode (i.e. sleep or hibernate), it doesn't do anything. This includes, in particular, the scheduler that handles waking up the thread that is monitoring the queue of timer events isn't running and so that thread isn't making any progress towards resuming execution to handle the next timer.
It's not so much that the event is explicitly postponed per se. But yes, that's the net effect.
In some cases, it's possible to use a timer class that doesn't have this issue. Both System.Windows.Forms.Timer and System.Windows.Threading.DispatcherTimer are based not on the Windows thread scheduler, but instead on the WM_TIMER message. Because of the way this message works — it is generated "on the fly" when a thread's message loop checks the message queue, based on whether the expiration time for the timer has passed…in a way, it's similar to the polling work-around described in the other answer to your question — it's immune to delays that would otherwise be caused by the computer being suspended.
You've stated your scenario involves a WPF program, so you may find that your best solution is actually to use the DispatcherTimer class, instead of System.Timers.Timer.
If you do decide you need a timer implementation that isn't tied to the UI thread, here's a version of System.Threading.Timer that will correctly take into account time spend while suspended:
class SleepAwareTimer : IDisposable
{
private readonly Timer _timer;
private TimeSpan _dueTime;
private TimeSpan _period;
private DateTime _nextTick;
private bool _resuming;
public SleepAwareTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
_dueTime = dueTime;
_period = period;
_nextTick = DateTime.UtcNow + dueTime;
SystemEvents.PowerModeChanged += _OnPowerModeChanged;
_timer = new System.Threading.Timer(o =>
{
_nextTick = DateTime.UtcNow + _period;
if (_resuming)
{
_timer.Change(_period, _period);
_resuming = false;
}
callback(o);
}, state, dueTime, period);
}
private void _OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (e.Mode == PowerModes.Resume)
{
TimeSpan dueTime = _nextTick - DateTime.UtcNow;
if (dueTime < TimeSpan.Zero)
{
dueTime = TimeSpan.Zero;
}
_timer.Change(dueTime, _period);
_resuming = true;
}
}
public void Change(TimeSpan dueTime, TimeSpan period)
{
_dueTime = dueTime;
_period = period;
_nextTick = DateTime.UtcNow + _dueTime;
_resuming = false;
_timer.Change(dueTime, period);
}
public void Dispose()
{
SystemEvents.PowerModeChanged -= _OnPowerModeChanged;
_timer.Dispose();
}
}
The public interface for System.Threading.Timer, and the subset interface above copied from that class, is different from what you'll find on System.Timers.Timer, but it accomplishes the same thing. If you really want a class that works exactly like System.Timers.Timer, it should not be hard to adapt the above technique to suit your needs.

System.Timers.Timer is a server based timer(elapsed event uses Threadpool. More accurate than other timers). When your computer goes in sleep mode or in hibernate mode, all the state of your program are stored in RAM. Same goes for your application state. Once your system is up your application state will be restored (along with the timer) by the OS. It wont be a good idea to "do something" or try to detect this events. Its possible from a Windows service though. Leave it to the OS to do its job.

An simple alarm class accepting an absolute Utc time that will survive a sleep cycle. The alarm can then be adjusted from the alarm callback to go off again. No periodic mode is supported to keep it simple. Based strongly on the answer from #PeterDuniho. Full disclosure: minimally tested.
using Microsoft.Win32;
using System;
using System.Threading;
class AlarmSleepTolerant : IDisposable
{
readonly Timer _timer;
DateTime? _alarmUtcOpt;
/// <summary>
/// Constructor
/// </summary>
/// <param name="callback"></param>
/// <param name="alarmUtcOpt"></param>
/// <param name="stateOpt"></param>
public AlarmSleepTolerant(TimerCallback callback, DateTime? alarmUtcOpt = null, object stateOpt = null)
{
SystemEvents.PowerModeChanged += _OnPowerModeChanged;
_timer = new Timer(callback, stateOpt, Timeout.Infinite, Timeout.Infinite);
SetAlarmTime(alarmUtcOpt);
}
/// <summary>
/// Set the current alarm, if alarmUtc is <= UtcNow, then the alarm goes off immediately.
/// Pass null to disable the alarm.
/// </summary>
/// <param name="alarmUtc"></param>
public void SetAlarmTime(DateTime? alarmUtcOpt = null)
{
lock (_timer)
{
_alarmUtcOpt = alarmUtcOpt;
if (!alarmUtcOpt.HasValue)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // disables the timer
}
else
{
TimeSpan dueIn = _alarmUtcOpt.Value - DateTime.UtcNow;
_timer.Change(dueIn.Ticks <= 0 ? 0 : (long)dueIn.TotalMilliseconds, Timeout.Infinite);
}
}
}
public void Dispose()
{
SystemEvents.PowerModeChanged -= _OnPowerModeChanged;
_timer.Dispose();
}
void _OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
// Timers are based on intervals rather than absolute times so they
// need to be adjusted upon a resume from sleep.
//
// If the alarm callback was missed during sleep, it will be called now.
//
if (e.Mode == PowerModes.Resume)
{
lock (_timer)
SetAlarmTime(_alarmUtcOpt);
}
}
}

Related

C# System.Timers.Timer - Please, how do I make it stop?

I've got a Timer that's doing a 60 second countdown. When the ticks hit 60 seconds, it stops and disposes - no problem (I think). This is run in the context of a WebApi service. I need to be able to cancel the countdown from a UI, so I've exposed a method to handle this. Since the controller is transient (thanks Luaan) and, as Daniel points out, the app pool is not predictable, I need a way to send a "cancellable" countdown to clients. Ideas anyone?
[HttpGet]
public IHttpActionResult CancelCountdown()
{
// DOES NOTHING BECAUSE THERE'S A NEW INSTANCE OF THE CONTROLLER
timer.Stop();
timer.Dispose();
return Ok();
}
private void StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
timer.Start();
}
private void BroadcastToClients(object sender, EventArgs e)
{
_elapsed += 1;
if (_elapsed == _duration)//_duration is 60
{
timer.Stop();
timer.Dispose();
return;
}
_messageHub.Clients.All.shutdown(_elapsed);
}
It's kind of hard to provide an adequate solution without knowing what you're trying to accomplish with this, but i'll give it a shot.
As Luaan pointed out, controllers are designed to be essentially stateless, so you shouldn't put instance variable on them except for it's external dependencies, since each request creates a new instance of the controller class.
You could store the timer on a static dictionary, indexed by a GUID, and return the GUID on your controller and use it as the cancellation token.
Something like:
private static Dictionary<string,Timer> timers = new Dictionary<Guid,Timer>();
public Guid StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
var guid = Guid.NewGuid().ToString();
timers.Add(guid,timer);
timer.Start();
return guid;
}
public IHttpActionResult CancelCountdown(Guid cancelationToken)
{
//If the timer no longer exist or the user supplied a wrong token
if(!timers.HasKey(cancelationToken)) return;
var timer = timers[cancelationToken];
timer.Stop();
timer.Dispose();
timers.Remove(cancelationToken);
}
However this won't solve the problem with the AppPool recycling. For a more robust solution, instead of using a timer, you could store the start date and time of each countdown in a more permanent storage (say an SQL database, a NoSQL databse, a redis server or whatever), and have a running thread or global timer, or something like Hangfire, initialized on startup, that constantly checks your countdown storage. If enough time has passed to send a broadcast message you send it, and mark the countdown as finished. If a user wants to cancel the countdown, the controller will simply read the appropiate record, mark it as cancelled, and your running thread can ignore it.
If you go with this approach, you'll need to take into account some considerations:
If the timer interval is set too short you could have a perfomance bottleneck for having to access a permament storage too often. If the interval is too long, the countdown won't be too precise.
To alleviate this problem you could store the countdowns start time in permanent storage, in case the app pool resets and you need to restore them. And also have them stored in memory on a static variable for quicker access.
Please note that if you're working with a server farm instead of a single server, static variables won't be shared across instances.

WPF DispatcherTimer Memory Issue

Edit: If useful, this project is on GitHub at https://github.com/lostchopstik/BetterBlync
I am building an application for the Blync status light using their provided API. This application polls the Lync/Skype for Biz client and converts the status to the appropriate light color. All aspects thus far work as expected, however when I leave this program running for an extended period of time, the memory usage grows until a System.OutOfMemory exception occurs.
I have narrowed the problem down to the DispatcherTimer holding the timer in memory and preventing it from being GCed. After reading some things online I found you could manually call for garbage collection, but this is bad practice. Regardless, here is what I have in my code right now:
private void initTimer()
{
timer = new DispatcherTimer();
timer.Interval = new TimeSpan( 0, 0, 0, 0, 200 );
timer.Tick += new EventHandler( Timer_Tick );
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
// Check to see if any new lights are connected
blync.FindBlyncLights();
// Get current status from Lync client
lync.GetStatus();
// Change to new color
setStatusLight();
if ( count++ == 100 )
{
count = 0;
GC.Collect();
}
}
The timer ticks every 200ms. I commented out all methods inside the timer and just let it run empty, and it still burned memory.
I am wondering what the proper way to handle this timer is. I've used the DispatcherTimer in the past and not had this issue.
I would also be open to trying something besides the DispatcherTimer.
If it is also useful, I have been messing with MemProfiler and here as my current graph with manual GC:
http://imgur.com/Iut91mF
It's a little hard to tell without seeing the rest of the code or the class the timer belongs to. I don't see anywhere you call Stop() on the timer. Does it need to be stopped?
You could also keep a local reference to the timer in whatever class you're in and call Start() and Stop() as needed.
If the timer never needs to be stopped and runs indefinitely, I would certainly look at what you're allocating as the timer runs and that's probably where your issue is.

How do I fire an event every 20ms *on average*? Inbuilt timer "creeps"

I'm writing an RTP server to publish PCMA wave files. It needs to pump data every 20ms (on average - it can be a bit either side of that for any 1 pump, but must average out at 20ms).
My current implementation uses a Timer, but then the event fires just over every 20 ms, so it gradually drifts out.
Is there a better way to do this? The only way I can currently think of is to dynamically adjust the timer inteval as it starts to creep, in order to bring it back in line.
Sample Code
void Main()
{
System.Timers.Timer timer = new System.Timers.Timer();
// Use a stopwatch to measure the "wall-clock" elapsed time.
Stopwatch sw = new Stopwatch();
sw.Start();
timer.Elapsed += (sender, args) =>
{
Console.WriteLine(sw.ElapsedMilliseconds);
// Simulate doing some work here -
// in real life this would be pumping data via UDP.
Thread.Sleep(300);
};
timer.AutoReset = true;
// I'm using an interval of 1 second here as it better
// illustrates the problem
timer.Interval = 1000;
timer.Start();
}
Output:
1002
2001
3002
4003
5003
6005
7006
8007
9007
10017
11018
12019
13019
14020 <-- By this point we have creeped over 20 ms in just 14 iterations :(
First of all: I will never get it to be exact because your program will never be in full control of what the CPU's are doing as long as you are running on standard Windows because it is not a real-time OS. Just think of a anti virus kicking in, the Garbage Collector freezing your thread, playing a game on the side, ...
That said you might be able to compensate a bit.
When the handler kicks in, pause the timer, record the current time, act, update the time's interval by setting the interval to the required interval based upon the start of the handler and the time it has taken to act.
This way you can control the creeping better. An exception to that might be when the acting takes longer than the interval and whether the interval should contain the time to act or be the time between to acts.
In my experience you cannot rely on any timer to get an interval that small (20 ms) accurately but compensating for creep can help quite a bit.
You could use StopWatch to measure time, but it doesn't have callbacks.
You can use Windows multimedia timer. It involves some WinAPI, but all the details are provided in this article.

Is there anything wrong with creating a timer for each instance?

For good understanding I will take a simple abstraction of DHCP lease as example: The lease contains the IP and MAC address, the time it was granted at and can be renewed with a given time span. Once expired an event will be invoked. Again, this is just serving as the most minimal example I could come up with:
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Timers;
namespace Example
{
public class Lease
{
public IPAddress IP
{
get;
private set;
}
public PhysicalAddress MAC
{
get;
private set;
}
public DateTime Granted
{
get;
private set;
}
public event EventHandler Expired;
private readonly Timer timer;
public Lease(IPAddress ip, PhysicalAddress mac, TimeSpan available)
{
IP = ip;
MAC = mac;
timer = new Timer();
timer.AutoReset = false;
timer.Elapsed += timerElapsed;
Renew(available);
}
public void timerElapsed(object sender, EventArgs e)
{
var handle = Expired;
if (handle != null)
{
handle(this, EventArgs.Empty);
}
}
public void Renew(TimeSpan available)
{
Granted = DateTime.Now;
timer.Interval = available.TotalMilliseconds;
timer.Enabled = true;
}
}
}
Is there anything to consider when creating - for example - "a few thousand" instances of such a class? I am mostly concerned about the timers. Should I consider another design pattern for such a task (like a manager for all the leases,or not use timers at all?) or is there nothing to worry about when creating a lot of timers, and this is the appropriate way? At least I always try to be cautious when it comes to timers and events.
Rather than creating thousands of timers, you could just store the expiration time of each Lease object, then in a single thread query for the expired ones periodically.
An off the top of my head code example:
var leases = new List<Lease>();
var running = true;
var expiredChecker = Task.Factory.StartNew(() =>
{
while (running)
{
var expired = leases.All(l => l.ExpirationDate < DateTime.Now);
// do something with the expired lease objects
}
});
Assuming you have an IEnumerable<Lease>, a DateTime property called ExpirationDate on your Lease object, you can then cancel this by setting running to false when you want to stop.
I would suppose this depends partly on what resources you have available on your server, and what kind of accuracy and performance you need.
An alternative approach might be to store something as simple as a time stamp in each instance, and checking that value regularly, comparing it to current time, and updating it appropriately. I have a hunch that this might be easier on performance - but you should try to benchmark it somehow to be sure.
Of course, if you have a large number of instances, iterating over all of them might also take some time, so perhaps pooling these into groups, where each group is handled in a separate thread on regular (adjustable?) intervals might be an option.
It's a bit hard to give a great answer here without some info about performance, so you should probably just create a proof of concept, and test a couple of strategies that you think might work, and try to benchmark them to see which fits best.
According to the System.Timers.Timer MSDN page:
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.
Which means it is not very likely to be causing issues when you are running a couple thousand timers at the same time.
That doesn't mean it is a good approach, you should probably be looking for a more centralized solution to this problem.
I recommend use a System.Threading.Timer instead of the System.Timers.Timer. The second one is wrapper about the first one to be visible in the design time and it is not necessary if you really don't need design time support. Timer internally calls ThreadPool.QueueUseWorkItem, than threadpool is responsible for maintaining thread on timer tick. Thread pool uses only one thread to maintain all the timers object and this thread decide when each timer queue new thread on timer tick.
Than I cant see any overhead unless your timers will tick so quick than you are not able do all on tick job and you simply queue too much work in thread pool.

System.Threading.Timer causing other Timers to fall behind

My first post here, but this site has answered many questions that I have had in the past. Hopefully I can give enough detail to explain the issue I am facing as I don't fully understand how all .NET is handling the threads I create!
OK so basically, I have a thread set to run every 1000ms which gets a frame counter from a video encoder and calculate the FPS. Accuracy is sufficient with a System.Threading.Timer for now though I realise it isn't accurate (often over 1000ms between events). I also have another Threading.Timer which is running and taking a reading from a network to serial device. The issue is that if the network device becomes unavailable and the socket timesout on that timer the FPS timers go completely out of sync! So they were previously executing every 1015ms (measured) but when I start this other Thread.Timer trying to make a socket connection and it fails it causes the FPS counter timers to go totally off (up to 7000ms!!). Am not quite sure why this should be and really need the FPS counter to run once a second pretty much no matter what.
Bit of code ->
FPS Counter
private void getFPS(Object stateInfo)//Run once per second
{
int frames = AxisMediaControl.getFrames; //Axis Encoder media control
int fps = frames - prevValue;
prevValue = frames;
setFPSBar(fps, fps_color); //Delegate to update progress bar for FPS
}
Battery Level Timer
while (isRunning)
{
if (!comm.Connected) //comm is standard socket client
comm.Connect(this.ip_address, this.port); //Timeout here causes other timer threads to go out of sync
if (comm.Connected)
{
decimal reading = comm.getBatt_Level();
//Calculate Readings and update GUI
Console.Out.WriteLine("Reading = " + (int)prog);
break;//Debug
}
This is the code used to connect to the socket currently ->
public Socket mSocket { get; set; }
public bool Connect(IPAddress ip_address, UInt16 port)
{
try
{
mSocket.Connect(ip_address, port);
}
catch(Exception ex)
{
}
return mSocket.Connected;
}
Hopefully not too ambiguous!
While I don't know why your FPS timer is not called for 7s, I can suggest a workaround: Measure the TimeSpan since the last time the FPS value was updated by remembering the Environment.TickCount value. Then, calculate the FPS value as (delta_frames / delta_t).
Thanks for the comments, I fixed it by doing the following.
Used a System.Timers.Timer instead and set auto-reset to false. Each time one of the timers completes I start it again, this means there is only ever one timer for each battery device. The problem with the initial solution is that the network timeout was causing the threads to stay alive for much longer than the timer interval. Thus, to ensure the timer interval was met a new thread was spawned more frequently.
During runtime this meant there was about 5-7 threads for each battery timer (whereby 6 are timing out and 1 is about to begin). Changing to the new timer means there is only one thread now as it should be.
I also added in the code to calculate the FPS based on the time taken (using Stopwatch function for higher accuracy (thanks USR)). Thanks for the help. I will have to make sure not to just leave exceptions blank too.

Categories