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