2

I need a function to run at a precise time within +/- 1ms. I have tried the following but end up with a 15ms minimum time between execution.

void Main()
{
    System.Timers.Timer timer = new System.Timers.Timer(1);   // executes every 15ms
    timer.Elapsed += new System.Timers.ElapsedEventHandler(myFunction);

    System.Timers.Timer timer2 = new System.Timers.Timer(5);   // executes every 15ms
    timer2.Elapsed += new System.Timers.ElapsedEventHandler(myFunction);

    System.Timers.Timer timer2 = new System.Timers.Timer(20);   // executes every 31ms
    timer3.Elapsed += new System.Timers.ElapsedEventHandler(myFunction);

    timer.Start();
    timer2.Start();
    timer3.Start();

}

void myFunction()
{
    doWord();
}

using Thread.Sleep() obtains the same results.

Synopsis of application.

I will be reading in a file that contains 1553 messages (each with a timestamp). I will need to replay these messages with as close as possible timing that the file contains. The timestamps for the messages are recorded in microsec, but I will only need msec accuracy.

This is done using a DDC 1553 card (PCI Card). I have an analyzer which allows me to view the messages including the delta time between messages to measure my accuracy.

The machine I'm using has a QuadCore with hyperthreading. Using a for(int i=0; .....) I can get accuracy to with .5msec. However this is very inefficient and would prefer to use a more realistic and even more portable method if possible.

Neal
  • 599
  • 8
  • 16
  • 1
    That is a really narrow time window, what are you wanting to do every ms? Keep in mind Timer events are typically raised by the ThreadPool, so they have to get a thread from the pool and raise the event, which takes time. – James Michael Hare Nov 01 '11 at 20:47
  • FYI: Never use `Thread.Sleep` for time sensitive tasks. IIRC, it guarantees that the thread will sleep for the time *at a minimum*, however the maximum time it could sleep is undefined. See [this](http://stackoverflow.com/questions/1303667/how-accurate-is-thread-sleeptimespan) question for a bit more info. Sorry I can't be more helpful with regards to your actual question. – Richard Marskell - Drackir Nov 01 '11 at 20:49
  • 2
    Timer resolution is 1/64 seconds, 15.625 msec. Pinvoking timeBeginPeriod and timeSetEvent can get you a 1 msec timer. Do not assume you'll actually get 1 msec consistently. – Hans Passant Nov 01 '11 at 20:59
  • Possible duplicate of http://stackoverflow.com/questions/4212611/raise-event-in-high-resolution-interval-timer – Nayan Nov 01 '11 at 21:11
  • @James: I'm doing 1553 Asyncronous messaging using a DDC 1553 Card. So I need the ability to send these messages over 1553 +/- 1ms. – Neal Nov 01 '11 at 21:34
  • @Drackir: I see I didn't realize Thread.Sleep did not have a standard resolution. The greater the interval I set the more accurate Thread.Sleep becomes. However, knowing what you said, I will never use Thread.Sleep again for timing sensitive functions. Thanks. – Neal Nov 01 '11 at 21:35
  • @Hans. I didn't realize Timer resolution was 1/64s, but your right, my function appears to fire with a minimum time of ~15.625msec. I'll look at using the Pinvoke and see if i can get better accuracy as you suggest. – Neal Nov 01 '11 at 21:37
  • @Hans - I'll mark your answer correct if you provide the answer. Your comment appears to give me what I can use. More testing in a harsher inviroment will determine its reliability. – Neal Nov 01 '11 at 22:24
  • Why don't you post an answer after testing it, that would be truly useful information. You can mark your own answer. – Hans Passant Nov 01 '11 at 23:13

4 Answers4

5

.NET, C#, and even Windows in general are not realtime OSes suitable for very fine timing.

The worst options include using the Timer classes and Thread.Sleep().

You can measure timing fairly accurately using the Stopwatch class, but in terms of accurately waiting for a set amount of time to pass.. there's no built-in mechanism.

If you could outline exactly what you are trying to do, assuming it's not motion control, hardware interfacing etc, there is probably a better solution than relying on very accurate timers.

Update; Neal: if you are interfacing with hardware in a timing-sensitive way, you should use a different solution. You can do a tight loop with Stopwatch, but it will use lots of CPU for as long as you do. And it won't be accurate enough, probably. E.g.: a PIC chip, an FPGA, an I/O card or interface, anything else basically.

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • I added a brief synopsis of what I'm trying to do. – Neal Nov 01 '11 at 21:45
  • I already added an update. Don't do it in software on Windows! – Kieren Johnstone Nov 01 '11 at 21:56
  • I'm interfacing directly with a PCI Card in the respective computer. I can get very accurate results using a loop as you suggest in your update, however, I have only tried this in a test enviroment so I'm not sure the realiability. There is no other choice but to use windows. The API for the card is a windows API. I think DDC has a Linux API as well, however, that may start causing issues later when I have to incorperate this project into a windows based GUI project. – Neal Nov 01 '11 at 21:57
  • I'm afraid that's still the answer. If you need to do something like that, you have to rely on something else other than Windows to do the timing. Most decent hardware IO has a buffer or its own programmable output; you can create a loop or timing on the hardware or give it a buffer of IO / timing information. The crux of it is still, you can't do it in Windows the way you want. Delegate the timing somewhere else. – Kieren Johnstone Nov 01 '11 at 22:00
  • I ended up using a seperate thread that runs 100% of the time using basic loops to deleay. Not really a good solution, however, I'm lacking in options. – Neal Nov 17 '11 at 22:33
1

You can use the high resolution timer but it is device depedant. You'll have to query for it. See this MSDN page for explanation: http://msdn.microsoft.com/en-us/library/aa964692%28v=vs.80%29.aspx

But System.Diagnostics.Stopwatch should aready give you precision near 1ms.

Krumelur
  • 32,180
  • 27
  • 124
  • 263
  • Stopwatch only times events, like a real stopwatch. You can't fire off an event on an interval. – Polynomial Nov 01 '11 at 20:52
  • Yeah, but he could have a loop or something on a separate thread and check if 1ms has elapsed and then trigger his method. – Krumelur Nov 01 '11 at 20:53
  • 1
    That would be ludicrously inefficient, and the context switch and thread scheduler granularity would most likely mean that the timing would be innacurate too. – Polynomial Nov 01 '11 at 20:57
  • Agreed. Maybe there is another way of achieving his goal with a totally different approach. But it's hard to tell without knowing the context. – Krumelur Nov 01 '11 at 21:05
1

You could use System.Threading.Timer which has reasonable accuracy. Just keep in mind that it doesn't post onto the UI thread, so you'll need to delegate any UI interaction properly.

You can also use the multimedia timer to do this, which has very high resolution timing. See http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx

Polynomial
  • 27,674
  • 12
  • 80
  • 107
  • This is the answer i was going to add. The `System.Threading.Timer` is a higher resolution than `System.Windows.Forms.Timer`. The alternative is to P/Invoke the multimedia timer (http://msdn.microsoft.com/en-us/library/dd743609(v=VS.85).aspx), designed for high-resolution timing events. Or use one of the many wrappers for C#. – Ian Boyd Nov 01 '11 at 21:17
  • System.Threading.Timer has the same accuracy as System.Timers.Timer apparently. So this doesn't help. – Neal Nov 01 '11 at 22:01
  • I'd suggest P/Invoking the multimedia timer then. It has very high precision. If you're dealing with hardware, the timing difference of even a few hundred nanoseconds will be significant. The time slices of threads are much larger than that, so you may have difficulty doing this in C#. You may want to consider writing a native driver that handles such events via interrupts - this will produce near-instant response times. – Polynomial Nov 02 '11 at 06:56
0

I have no idea how to do something like this in a modern version of Windows - just stumbled across this old question and recalled I faced a similar problem an even longer time ago...

Back in the stone age (Win 3.11 and later Win95), I was able to obtain very high and repeatable real time performance (10kHz was no problem, jitter was pretty decent as well - in the microsecond range on a 90MHz Pentium) by reprogramming the real-time interrupt and hooking into the timer's Non Maskable Interrupt. At the time this involved a VxD (virtual device driver) to be able to directly access the timer. Also needed to obtain a dedicated shared memory space and code in assembly (could probably mix assembly with C/C++ - obviously, the higher the frequency, the tighter the loop needs to be).

Basically I reduced the timer's period to the one I desired, then executed my code - it would periodically call back into the OS so that the OS would experience the interval it was expecting. Also needed to hook the functions that the OS used to adjust the interval and adjust my callbacks accordingly (assuming my code was always running at a higher frequency than the OS wanted). Actually used it to do motion control via the printer port. Never made it into released software but did get a basic bench CNC going.

The code stopped working well by Win98 and I never tried my hand at it again. Accessing the hardware has gotten more complicated and almost always "virtualized" in some way.

I would start by looking at device driver programming and possibly games (e.g. Direct X) when trying to obtain some type of RTOS performance outside a dedicated RTOS environment.

mszil
  • 61
  • 2