Task Delay vs Thread Sleep Resolution Accuracy - c#

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

Related

C# Best way to schedule recurring task in an efficient windows service

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.

Possible causes for thread/timer delay?

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.

How to execute code at a specific exact time (far from now) in C#?

I am developping a Windows Service that has to execute a method at a specific exact time.
When the service starts, it extracts several different DateTimes from an SQL Server database and should then start a thread for each DateTime. Each thread should wait until the exact DateTime value, then do some work, then wait again for a shorter period of time and then do some final work again.
I don't want to use System.Timers.Timer because:
the method has to be executed at the exact specified time
this exact time could be in more than 24h
I need to pass a parameter to the Elapsed event
How can I implement this?
Thank you.
EDIT: I just had an idea last night, what if I write a dynamic polling timer? For exemple, if the due datetime is in more than 12 hours it can poll the time every hour to re-synchronize. Then if the due datetime is in more than 3 hours it can poll the time every 30min and so on... What do you think? Would that be a bad code to write?
Thank you again.
You can't pass a parameter to the tick event with System.Timers.Timer, but you can with System.Threading.Timer. The delay time "greater than 24 hours" is no problem. The timers use a 32 bit period that is expressed in milliseconds. 2^31 milliseconds works out to something like 24.85 days. There's also an overload that lets you specify the delay with a 64-bit signed integer. 2^63 milliseconds is ... several hundred million years.
But having those timers tick at an exact date/time far in the future is problematic because you have to specify the delay time, and a clock change will cause your delay to be too short or too long (think Daylight Saving Time, or user-initiated time changes). You can specify the tick time and have a timer poll the current time every second. It's kind of ugly, but it works.
Another option is to use the Windows Waitable Timer object, which lets you set an exact date and time. Unfortunately, the Framework doesn't include a corresponding object. I wrote an article about it some years ago and published the code. The article is no longer available online, but you can download the code from http://mischel.com/pubs/waitabletimer.zip.
I have used something called ManualResetEvent in the past with a lot of success. Assuming that you know the exact time to run your code then you will be able to calculate estimated time to run (TTR) and subsequent runs should be configured within the first run.
partial class SomeService : ServiceBase
{
private ManualResetEvent stop = new ManualResetEvent(false);
private List<DateTime> times;
private int idxDT = 0;
public SomeService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.stop.Reset();
//implement you logic to calculate miliseconds to desired first run time
int miliseconds_to_run = 1;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
private void ThreadFunc(object _state, bool _timedOut)
{
if (_timedOut)
{
if(this.times == null)
{
//get a list of times to run, store it along with the index of current TTR
this.times = new List<DateTime>();
}
int miliseconds_to_run = (this.times[this.idxDT++] - DateTime.Now).Miliseconds;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
}
protected override void OnStop()
{
this.stop.Set();
}
}
Of course this highly depends how exact your job start time has to be. ThreadPool class will send a Thread alocation request to the OS, and then it will wait for the next available Thread from the Pool. In some processes with lots of lots of threads this could lead to Thread starvation and your exact times will be late.
You could also try creating Task Scheduler Jobs from .NET but I've never done that before.
Even though you said you don't want to use System.Timers.Timer I'll show you how to do it anyway, as bullet 1 and two in your question don't seem to be valid points against using it in my opinion.
So here's what I do in several applications of mine:
// 1. Create the timer
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += ...;
// 2. Calculate the number of milliseconds between the scheduled time and the current time
timer.Interval = (scheduledDate - DateTime.Now).TotalMilliSeconds;
// 3. Start the timer
timer.Start();
Done. The event will fire "roughly" at the desired time. Please note that this doesn't work down to the exact millisecond, as Windows is not a real-time OS.
I did face sort-off similar issue and used below solution which might solve your issue.
I used ManualResetEvent class, added a Wait method and made the service wait for the exact time.
protected ManualResetEvent waitEvent = new ManualResetEvent(false);
protected bool Wait(int milliSecs)
{
return !this.waitEvent.WaitOne(milliSecs, true);
}
I used this Wait in OnStart method as below:
protected override void OnStart(string[] args)
{
DateTime nextRun = dt;//datetime from the database
YourProcessOrThreadToRun process = new YourProcessOrThreadToRun();
while (Wait((int)nextRun.Subtract(DateTime.Now).TotalMilliseconds))
{
process.StartProcess();
}
}
YourProcessOrThreadToRun is the thread you want to run on that exact time.

Periodic Tasks in C# without the use of ThreadPool

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());
}
}

Timer Delay Degrades or becomes inconsistent over time?

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;
}

Categories

Resources