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());
}
}
Related
I write a Windows Service in .Net Framework 4.0 and I need to schedule a recurring task inside. New task can only run if previous one is finished, so no tasks in parallel...
All my task occurences work on same object (WCF Channel factory).
A task takes almost 2 seconds to complete and may be scheduled every 2 seconds or every hour.
My constraint is to have this Windows service as invisible/light as possible on memory and processor uses point of view...
I've already found these 2 ways:
Use a System.Timers.Timer with Autoreset to false => I've to
implement an ElapsedEventHandler and pass my shared object (WCF
Channel factory)
Use a never ending loop: not sure of mem/proc use in
that state but no threads aspect to take care of.
Any suggestions?
Thanks and have a nice day!
For me was fine following: I'm started timer once, then in Tick method I will schedule next Tick call. Like this:
private Timer _timer;
//Interval in milliseconds
int _interval = 1000;
public void SetTimer()
{
// this is System.Threading.Timer, of course
_timer = new Timer(Tick, null, _interval, Timeout.Infinite);
}
private void Tick(object state)
{
try
{
// Put your code in here
}
finally
{
_timer?.Change(_interval, Timeout.Infinite);
}
}
// dont forget to dispose your timer using await _timer.DisposeAsync(); or _timer.Dispose();
System.Timers.Timer is the way to go and will have little to no system performance impact. Current systems can handle thousands of timers.
Since you want the timer to continue, don't set AutoReset, but you will need a way to change its interval (if that's what you need).
Your service instance should hold an instance of your WCF channel factory.
To ensure synchronous processing, you should implement an Interlocked protected flag, like a long, which can serve as an indicator of busyness. If equal to one, for example, the method that kicks off processing from timer elapsed event will simply return. Once processing is complete, at which time you set the flag to zero, further timer elapsed events will be able to enter and kick off processing again.
Remember to stop, restart, and dispose of your timer in the various service events, like pause, stop, start.
i need to execute a function after a specific amount of time, therefore i use this code.
_start = DateTime.Now;
await Task.Delay(_app.Settings.AudioFileStartVarianz.BaseSpan).ContinueWith(x =>
{
Console.WriteLine(DateTime.Now - _start);
});
Lets say i want to wait for exactly 0.04 seconds. My problem now is that it's not working precise enough. I get following output after calling the function 5 times:
00:00:00.0414220
00:00:00.0536098
00:00:00.0507841
00:00:00.0467757
00:00:00.0425790
if i use this code it works way better
_start = DateTime.Now;
Thread.Sleep(_app.Settings.AudioFileStartVarianz.BaseSpan);
Console.WriteLine(DateTime.Now - _start);
00:00:00.0405879
00:00:00.0404284
00:00:00.0402117
00:00:00.0404908
00:00:00.0409088
But now i have the problem, that the function is not running asynchronous, what is bad because i am playing an audio file (NAudio).
Any ideas how i can here wait async, so that my audio file is not stopping?
KR Manuel
The difference between the two calls, Thread.Sleep & Task.Delay, is that Thread.Sleep calls an OS method to sleep the thread and Task.Delay creates a Timer to simulate the delay.
The calls are effectively...
private static extern int WaitOneNative(SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
...and...
promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite);
...respectively.
Now timers in windows are notoriously low resolution - with a 15ms error or so. I think it's because of this that you're getting your results.
The bad news is that sleeping the thread is not asynchronous, as you stated, so to get asynchrony you need to accept the timer resolution error. I don't think that there is any sane way for you to avoid it.
To get an accurate timer you should use a multimedia timer :
Multimedia timer services allow applications to schedule timer events
with the greatest resolution (or accuracy) possible for the hardware
platform. These multimedia timer services allow you to schedule timer
events at a higher resolution than other timer services.
You can find an implementation there :
http://www.codeproject.com/Articles/5501/The-Multimedia-Timer-for-the-NET-Framework
So for your example it can be something like
EDIT code simplified :
Multimedia.Timer mmTimer = new Multimedia.Timer(new Container())
{
Mode = Multimedia.TimerMode.OneShot,
Period = 40,
Resolution = 1,
SynchronizingObject = this
};
mmTimer.Tick += new System.EventHandler(this.mmTimer_Tick);
startTime = DateTime.Now;
mmTimer.Start();
private void mmTimer_Tick(object sender, System.EventArgs e)
{
MessageBox.Show("ticks after 40ms");
}
Dont try to check if the timer ticks correctly with DateTime.Now the precision of this is around 15 or 16 ms depending on the system.
Further reading : http://www.nullskull.com/articles/20021111.asp
In relation to a previous question of mine ([question] : Which thread will timer method run in? ), I've added a Timer to my Windows Forms app to run every 100ms to show how long the program session has been running. I've defined it as follows (these are only the snippets relevant to the timer):
private System.Timers.Timer timerPureTime = new System.Timers.Timer(100);
timerPureTime.Elapsed += new System.Timers.ElapsedEventHandler(updateTimeElapsed);
this.timerPureTime.SynchronizingObject = currentForm; //where currentForm is my main Form
public void updateTimeElapsed(object sender, ElapsedEventArgs e)
{
if (currentForm.lblTimeElapsed.InvokeRequired) //lblTimeElapsed is your standard Windows Form label
{
currentForm.lblTimeElapsed.Invoke((MethodInvoker)delegate //also, trying to make make GUI invoking thread-safe here
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
});
}
else
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
}
purelyTime += 0.1;
}
As I understand it the Timer should be running in a thread of its own (taken from the Threadpool) however it still experiences some delay every now and then, throwing the timer off-course. Other threads within the application run pretty regularly (every 250ms) and computation-intensive, but shouldn't these be independent of Timer threads?
What could be the possible causes for timer lag in such cases?
Windows cannot guarantee a precisely regular callback for a timer, so you will definitely see that kind of variance.
You need to take a different approach:
Initialise a Stopwatch field in your class.
Call Stopwatch.Restart() when you want to reset the timing.
Inside updateTimeElapsed() use Stopwatch.Elapsed instead of purelyTime.
Note that your code is completely ignoring the amount of time spent in the timer handler function itself. Inside the handler, you are using Invoke to send a message to the UI and waiting for it to return. That can take an arbitrary amount of time, particularly if the UI is busy.
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.
I'm hoping someone can shed some light on what might be happening for me. Here's a summary of whats happening.
I have an application that does lots of "stuff". Its a pretty hefty application that does lots of number crunching using many threads. There are several timers that are used. Over a long period of time, the timers stop consistently invoking the elapsed handler.
For instance: I have a timer set to elapse every second. After a period of hours the timer starts randomly triggering late. If I do not restart the application the performance just degrades and the timers fire later and later eventually turning into 3 or 4 seconds, forcing me to restart the application. I have not been able to identify any leaks. CPU usage does not go up, memory does not go up, and the server is no where near being maxed out. Can anyone give me some ideas as to what may be causing this?
private void Timer_Elapsed(object source, ElapsedEventArgs e)
{
if (seconds > 0)
{
seconds--;
timer.Start();
}
}
Is it possible you're exhausting the thread pool? Most timers invoke the handler using a threadpool thread. If all threadpool threads are in use, it will just get queued until one is available.
If that's the case switch some of your processing to use your own threads, not threadpool threads.
To test if you're exhausting the thread pool start up a background thread that periodically (a few times a second) checks ThreadPool.GetAvailableThreads and logs a message when the available is small (even if it's never actually zero when you check, if it sometimes approaches zero then it's likely this is the problem).
The size of the pool can be changed with ThreadPool.SetMaxThreads although that may not be the best solution. If you're using threadpool threads for longer running tasks, stop it. For long-running tasks use your own threads.
the timer class you use is really important
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
but I don't think the problem is the timer itself,
for instance try making an application using the same timer class
that ONLY writes the current DateTime to a log file
and leave it running for an extremely long period of time, you'll see that there's no such a 3/4 seconds delay
review your timer code and check that no shared resources are being accessed at the same time,
maybe the Timer is OK, but there's a bottleneck in the event handler function or in "something" that function uses
Sounds like maybe it's not really the same timer, and so the resources being "leaked" here are GDI handles.
Possible workaround:
DateTime mayContinue = DateTime.MinValue;
bool blockingUi = false;
private void Timer_Elapsed(object source, ElapsedEventArgs e)
{
if( blockingUi )
{
if( DateTime.Now < mayContinue )
{
// Notify time remaining
// Update the UI with a BeginInvoke
}
else
{
blockingUi = false;
// Notify ready
// Update the UI with a BeginInvoke
}
}
}
private void BlockUi()
{
mayContinue = DateTime.Now.AddSeconds(30);
blockingUi = true;
}