Need events to execute on timer events, metronome precision

I setup a timer to call an event in my application. The problme is the event execution is being skewed by other windows operations. Ex. openning and window, loading a webpage. I need the event to excute exactly on time, every time.

When i first set up the app, used a sound file, like a metronome to listen to the even firing, in a steady state, its firing right on, but as soon do something in the windows environment, the sound fires slower, then sort of sppeds up a bit to catch up.

So i added a logging method to the event to ctahc the timer ticks. From that data, it appears that the timer is not being affected by the windows app, but my application event calls are being affected. I figured this out by checking the datetime.now in the event, and if i set it to 250 milliseconds, which is 4 clicks per second. You get data something like below.

(sec):(ms)

1:000 1:250 1:500 1:750

2:000 2:250 2:500 2:750

3:000 3:250 3:500 3:750

(lets say i execute some windows event)(time will skew)

4:122 4:388 4:600 4:876

(stop doing what i was doing in windows) (going to shorten the data for simplicit, my list was 30sec long)

5:124 5:268 5:500 5:750

(you would se the time go back the same milliseconds it was at the begining)

6:000 6:250 6:500 6:750

7:000 7:250 7:500 7:750

So i'm thinking the timer continues to fire on the same millisecond every time, but its the event that is being skewed to fire off time by other windows operations. Its not a huge skew, but for what i need to accomplish, its unacceptable.

Is there anyhting i can do in .NET, hoping to use XAML/WPF application, thats will correct the skewing of events?

thx.

Answers


Doing that right could be very, very tricky, if possible at all. Certain audio processing applications really struggle hard to do that. Standard Computer setups are not exactly made for this kind of realtime operation, because you can't control how many threads / processes will run in the background.

However, as a first attempt, you could use a loop instead of an asynchronous trigger. Note that this might grow heavy on the CPU and still does not guarantee precise timing. Pseudo-Code:

forever
{
     // This will bring your precision down to the level of thread 
     // timing precision
     Sleep(0); 

     LastTime = GetPerformanceTimer();
     if(LastTime > NextInterval)
     {
         // Play sound, update last time
     }
}

where GetPerformanceTimer is some kind of QueryPerformanceCounter based method. I wrote a very simple profiler once http://www.emphess.net/2009/03/04/a-very-simple-profiler/, but the code in there is very easy and basically gives you the time in seconds since the timer started with very high precision.

You might also want to give your process higher priority so other processes will not stall your process.


I would expect the timer to fire pretty close to exactly on time, as you have observed. However, even than can be affected if the computer is processor bound.

It appears that you want the events to occur on your UI thread exactly on time, and that's going to be a problem. Code that updates the UI has to execute on the UI thread. If anything else is happening on the UI thread when the timer fires, the update operation from the timer has to wait.

I consider it unlikely that you'll be able to get the UI to update exactly on time because there's too much variability in what's going on at any particular moment. This will be especially true on a single processor machine.

If you don't need to update the UI, you can get slightly more consistent response by using a System.Threading.Timer with a callback method reather than using one of the timers that uses events. Still, I would be very surprised if you could get any timer-based method to work reliably in this application.


Need Your Help

LINQ to SQL query not ordering properly, please help

c# linq-to-sql

var temp = (from assetVisit in db.AssetVisits

Issues getting JTDS driver to accept sendStringParametersAsUnicode=false?

java sql-server hibernate jtds sqljdbc

Been using net.sourceforge.jtds.jdbc.Driver as my driver from MSSQL for all my applications. I had trouble with performance in a prepared statement, and learned that sendStringParametersAsUnicode=f...