I'm writing a code where:
I.)
The user adds "events" during run-time. (To a flowlayoutpanel) These events are turning some LEDs on/off, after "x" time has elapsed and the LED-turning functions are written in a Led-function.cs class.
i.e:
1) Turn left led on After 3500ms
2) Turn right led on After 4000ms
II.)
When the user hits start a timer starts.
// Create timer.
System.Timers.Timer _timer;
_timer = new System.Timers.Timer();
_timer.Interval = (1);
_timer.Elapsed += (sender, e) => { HandleTimerElapsed(LedObject, device, _timer); };
_timer.Start();
III.)
The timer's tick event is raised every millisecond and checks if the user definied time has ellapsed. Im measuring the elapsed time with adding +1 to an integer at every tick event. (NumberOfTicks++;)
//Timer Handle
private void HandleTimerElapsed(Led_Functions LedObject, string device, System.Timers.Timer _timer)
{
NumberOfTicks++;
if (NumberOfTicks >= Start_time[0])
{
LedObject.LeftLED_ONnobutton(device);
}
}
IV.) What I noticed was that when the tick was set to 1. (So the tick event is raised every millisecond) Even if I set 3000ms to the evet the LED actually flashed around 6 seconds.
When the tick was set to 100. (So every 0,1s) then the flash was more accurate (3,5sec or so).
Any Ideas why im having this delay in time?
Or do you have any ideas how could I implement it better?
Thank you!
1ms is a really small interval for CPUs. You cannot ensure your code get called every 1ms especially when the system has some heavy work to do.
A better implement is to use DateTime.Now - startTime to get the time span or use Stopwatch.
private Stopwatch stopwatch = new Stopwatch();
// start the stopwatch:
stopwatch.Start();
// Timer Handle:
numberOfTicks = stopwatch.ElapsedMilliseconds;
Related
I am displaying time in my application using(basically in a label Datetime.Now formatted as hh:mm:ss tt) using a DispatcherTimer.
_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 1)};
_timer.Tick += _timer_Tick;
_timer.Start();
private void _timer_Tick(object sender, EventArgs e)
{
try
{
var now = DateTime.UtcNow;
var nowUserSelected =
TimeZoneInfo.ConvertTimeFromUtc(now,
(DataContext as MainViewModel)?.UserSelectedTimeZone ?? TimeZoneInfo.Local);
ClockCurrent.Text = $"{nowUserSelected:hh:mm:ss tt}";
}
catch (Exception exp)
{
Log.Error("Error occurred while reporting time", exp);
}
}
The issue is that if the user opens a the Clock from the task bar(if you click on the time in the task bar there is pop up which displays the current time including seconds) sometimes the time in my app appears to be off by one second(sometimes!). Which I believe could be happening because the timer must be set to tick every second from the current time which could be 10:50:53 PM and 950 ms and it might be lets say and then it ticks every 54 and 950 ms ..... ms and so on , and since I am only displaying time till seconds it gives the illusion i am behind a whole second.
What is the recommended way to show the time which matches the time shown by the task bar, maybe set timer interval to tick every 500 ms ?
Check the ms when you are starting. Do first refresh right after full second, next refreshes each second
Even better: at the end of UI update you determine when the next UI update must happen.
#iPirat is correct, but I guess others did not understand what he meant, so let me first explain what is the problem and then how to solve it.
The DispatcherTimer runs on the WPF GUI thread. The advantage of this is that the code of DispatcherTimer.Tick can access any WPF control. The disadvantage is that once the 1 second since the last tick has expired, the WPF GUI thread might be busy with something else and the tick fires few milliseconds later. The next time Tick gets execute, there will be another small delay and this accumulates until the summed up delay becomes bigger than 1 second and you "loose" one tick.
You can prevent that by changing DispatcherTimer.Interval during each tick. If you want a tick every 1000 milliseconds and the tick was executed x milliseconds too late, you set DispatcherTimer.Interval to 1000-x milliseconds.
const int constantInterval = 1000;//milliseconds
private void Timer_Tick(object? sender, EventArgs e) {
var now = DateTime.Now;
var nowMilliseconds = (int)now.TimeOfDay.TotalMilliseconds;
var timerInterval = constantInterval -
nowMilliseconds%constantInterval + 5;//5: sometimes the tick comes few millisecs early
timer.Interval = TimeSpan.FromMilliseconds(timerInterval);
}
By the way, you might want to increase the priority like this DispatcherTimer timer = new DispatcherTimer (DispatcherPriority.Input);. This will make the delays a bit smaller, but the GUI gets still rendered fast enugh.
For more details see my article on CodeProject: Improving the WPF DispatcherTimer Precision
I am building an alerter service (windows service) in c#. This service will start and do a few api calls. based on the result I get from the calls and the setting that apply to that user an other method will fire after x amount of time. This goes on until the user stops the service.
The time in between the calls to the methods can be variable. So after startup the first method call can be after 1 min, after that the next call can be after 5 min, the call after that can be after 10 min. All depends on the response I get from the API.
I have been looking into system.timers, but every example i find has a fixed time the event fires so that does not fit my needs.
Define the time variable globally and after each response reset the interval time
FYI
1 Minute = 60000 so for 10 Minutes aTimer.Interval=60000 * 10;
use it like this
//defined globally
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);
//api call goes here
aTimer.Interval=5000; // here you can define the time or reset it after each api call
aTimer.Enabled=true;
Use a one-shot timer, and reset it after every call. I typically use System.Threading.Timer for this:
// When you first create the timer, set it for the initial time
Timer MyTimer = new Timer(TimerCallbackFunction, null, 60000, Timeout.Infinite);
Setting the period to Timeout.Infinite prevents the timer from ticking multiple times. It'll just tick once and then wait indefinitely, or until you restart it.
In your timer callback, do whatever needs to be done and then reset the timer:
void TimerCallbackFunction(object state)
{
// Here, do whatever you need to do.
// Then set the timer for the next interval.
MyTimer.Change(newTimeoutValue, Timeout.Infinite);
}
This prevents multiple concurrent callbacks (if your timeout value is too short), and also lets you specify when the next tick will be.
Is there a way to execute a periodic task/thread in C# without the using of a thread pool (this is one of the main requirements I have).
The expected scenario is as the following:
The periodic thread blocks/waits for a timer event (from the system).
The system notifies the thread when the timer expires.
The thread executes some code.
The thread blocks/waits for the next timer event from the system (note that if the thread missed one or more timer events, this is ok).
The closest thing I found to this is the System.Forms.Timer, but the issue is that its accuracy is limited to 55ms which is not enough for me.
The System.Timers.Timer seems to be able to handle this via the SynchronizingObject property. However, I'm not really sure how to implement a ISynchronizeInvoke according to the above scenario. All of the code samples I found for implementing ISynchronizeInvoke seem too complicated for handling such a simple scenario.
Is there a way to easily implement this feature in C# as in the above scenario (without using threadpools) and more accurate than the System.Forms.Timer?
Windows timers have a default resolution of 15.6 ms, from their documentation:
The default system-wide timer resolution in Windows is 15.6 ms, which
means that every 15.6 ms the operating system receives a clock
interrupt from the system timer hardware. When the clock interrupt
fires, Windows updates the timer tick count and checks whether a
scheduled timer object has expired. Some applications require that
timer expiration is serviced more frequently than once every 15.6 ms.
They also state:
Applications can call timeBeginPeriod to increase the timer
resolution. The maximum resolution of 1 ms is used to support
graphical animations, audio playback, or video playback. This not only
increases the timer resolution for the application to 1 ms, but also
affects the global system timer resolution, because Windows uses at
least the highest resolution (that is, the lowest interval) that any
application requests. Therefore, if only one application requests a
timer resolution of 1 ms, the system timer sets the interval (also
called the “system timer tick”) to at least 1 ms. For more
information, see “timeBeginPeriod Function” on the MSDN® website.
So if you really need high resolution timers, you can use the timeBeginPeriod call to affect the global system timer, but know that it will affect the batter life/power consuption of the device on which it is working.
Also, there are the QueryPerformanceCounter and QueryPerformanceFrequency calls that can be used to get lower levels of precision in .net, like in this example: http://www.codeproject.com/Articles/571289/Obtaining-Microsecond-Precision-in-NET
Multimedia Timers will provide you with the highest resolution of all timers. If you really and truly need 10ms or less resolution, that will be the only way to go.
If you find that you do not need the resolution provided by Multimedia Timers, you will find that Waitable Timers will give you the ability to code a loop that waits for a timer to expire within a single thread.
You also may choose Timer Queues which provide a large number of timers without the resource overhead of the other timers, but by default uses the system thread pool.
Have you tried to simply sleep your thread?
int msecSleepTime = 25; // number of milliseconds to sleep
Thread.Sleep(msecSleepTime); // sleep the current thread for the given number of milliseconds
Quickest response from System.Timers.Timer on my system w/o reconfiguring the system's timer is ~16 ms. Set your Timer.Interval value to (int)( target interval / 16 ) * 16 then have the thread sleep for the remaining duration (and if you really need better accuracy, an interpreted language such as C# is not the correct choice):
class Program
{
private static Timer _timer = new Timer();
private static DateTime _last = DateTime.Now;
private const int IntendedInterval = 25;
static void Main(string[] args)
{
_timer.AutoReset = false;
_timer.Interval = (int)(IntendedInterval / 16) * 16;
_timer.Elapsed += _timer_Elapsed;
_timer.Start();
Console.ReadLine();
}
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
var now = DateTime.Now;
var duration = now - _last;
var sleep = IntendedInterval - duration.TotalMilliseconds;
if (0 < sleep )
{
System.Threading.Thread.Sleep(( int )sleep);
}
_timer.Start();
now = DateTime.Now;
duration = now - _last;
_last = now;
Console.WriteLine(duration.TotalMilliseconds.ToString());
}
}
I have created a windows service.In which I have set the timer interval for every one minute and so it was triggering for every minute,. But I need to trigger the same for each day..
You can find the code below where I have set the timer interval in OnStart() method..
Code:
protected override void OnStart(string[] args)
{
TraceService("start service");
//handle Elapsed event
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
//This statement is used to set interval to 1 minute (= 60,000 milliseconds)
timer.Interval = 86400000;
//enabling the timer
timer.Enabled = true;
}
This post is quite old but I think it's worth mentioning that instead of using a magic number like 86400000 it's better to use something like new TimeSpan(1, 0, 0, 0).TotalMilliseconds , so that if someone needs to change it they will know what should be changed.
So, couple of things regarding your post:
First, it does not state what is the problem!
Technically, Timer supports a timer interval of about 25 days.
So, your code should work.
If you want to exceed 25 days and you are not concerned about thread safety, I suggest you go to System.Threading.Timer.
More info here
Since, your service runs as a windows based service, i suggest you go to System.Threading.Timer.
In C# now you can use TimeSpan class to get total milliseconds in day to set a per day timer.
var totalMilliSecondsPerDay = TimeSpan.FromDays(1).TotalMilliseconds;
var timer = new Timer(totalMilliSecondsPerDay);
I am trying to get a timer run every minute in sync with the system clock (00:01:00, 00:02:00, 00:03:00, etc). Will the following code produce a stable timer? I've tried running it. The timer does precisely run every min. But the question is will it start to wander off, say, after several months?
private System.Timers.Timer timer;
public frmMain()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = GetInterval();
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do processing
timer.Interval = GetInterval();
timer.Start();
}
private double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
It won't.
DateTime.Now uses the system clock as the reference timer, so your timer will always stay in sync with it, modulus the few milliseconds of system clock resolution.
I don't see how it can wander off, everytime the timer ticks, it determines how long it is to the next exact minute and sets the interval accordingly. In theory it is actually quite ingenious, because I timer by itself would wander off. The only way to know for sure would be to test it of course, so as long as your UI doesn't freeze for more then 60 seconds, (maybe 50s to play it safe) there won't be a problem. Keep in mind that laptops will often go to sleep when left for a time, or the lid is closed, this will cause a glitch.
Depending on what you are attemping to do though, why not just use the system time, to send an event everytime the minute changes?
The big picture looks fine, GetInterval will always return a positive value, and so on. I only see a few caveats:
If standby/resume happens then you may have one run at a non-round time
If timer_Elapsed takes more than a minute to complete then you will miss a beat
If the system is so overloaded that timer_Elapsed is scheduled 40/50 seconds in delay AND timer_Elapsed takes more than 60 - delay seconds, you will miss a beat
Your code won't drift, but there will (inevitably) be jitter as Timer callbacks are rarely bang on the requested interval.
The only potential problem I can see with this code is if the ThreadPool were under such strain that your timer callback was not dequeued and executed within a minute interval, resulting in a skipped minute.
This seems somewhat unlikely, but not completely beyond the realms of possibility.