2

I'm making simple stroboscope attached to computer. I have Loop Like that:

double SleepTime = 1000 / Hz;

while ()
{
    BlinkAll();
    Thread.Sleep((int)SleepTime);
}

But this is very inaccurate. If Hz = 666 than SleepTime = 1.5 and (int)SleepTime = 1

this means that on output I get 1000Hz not 666Hz This is big diffrence.

How to fix this?

P.S.

This example is still not to accurate. It's better but not good in any way:

double SleepTime = 1000 / Hz;
Thread.Sleep((int)SleepTime + 0.5)
Hooch
  • 28,817
  • 29
  • 102
  • 161
  • 5
    `Threading.Sleep` is inaccurate up to 15ms, as far as I know and remember. It's not usable for such a task, not even closely. – Bobby Jan 08 '11 at 22:35
  • 3
    Actually, the precision is not even close to that. Although you can specify a granularity of milliseconds, the interrupt that is used has a lower frequency, typically at about 10 milliseconds (differing between different operating system versions). That means that you actually get something like 100 Hz rather than 1000 Hz. – Guffa Jan 08 '11 at 22:40
  • 1
    You might want to have a look at this question: [How accurate is Thread.Sleep()](http://stackoverflow.com/questions/1303667/how-accurate-is-thread-sleeptimespan) – Bobby Jan 08 '11 at 22:42
  • What if you `Sleep(0)` (that is the absolute minimum sleep time and means "...this thread should be suspended to allow other waiting threads to execute..."). *Then busy-loop with higher-precision timers*. This will be the *best* one can do with `Thread.Sleep`, but still does not come with any guarantees. The code will need to account for "missed" cycles as well. –  Jan 08 '11 at 23:36
  • @pst: This still will be, most likely, something between 10ms and 25ms. `Thread.Sleep()` does not have this kind of granularity. On the other hand I'm not sure if you'll ever get such precision on a non-realtime-os. – Bobby Jan 09 '11 at 11:50
  • @Bobby I don't disagree and believe the information provided. I was merely pointing out the *best* situation that can result with `Thread.Sleep()` as a test-case -- ignoring any thread/process/switch overheads and CLR (GC) non-determinism :-) If the *ideal/best* situation is eliminated, then so is `Thread.Sleep()` as an approach in general. –  Jan 09 '11 at 22:25
  • @pst: Oh, I see. You're, of course, right. As a test-case or theoretical example it works. – Bobby Jan 10 '11 at 07:58

3 Answers3

2

Take a look at NtDelayExecution (ntdll.dll)... it seems to have better granularity (units of 100-ns rather than 1 ms), although I'm not sure how much that will help because I think that threads on Windows take a few milliseconds of time slice each.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • 2
    Yeah, you're just not going to get that level of granularity or consistency on a non-RTOS. – Ed S. Jan 08 '11 at 22:55
0

have you tried with System.Timers.Timer? I believe it's much more accurate and accept milliseconds so you can be quite accurate

Juliet
  • 80,494
  • 45
  • 196
  • 228
smnbss
  • 1,031
  • 1
  • 10
  • 21
0

How about something like:

using System;
using System.Threading;
using System.Diagnostics;

static class Program
{
    static void Main()
    {
        const int Hz = 666;
        var t0 = DateTime.Now;
        int nCycles = 0;
        var sw = Stopwatch.StartNew();
        while (sw.ElapsedMilliseconds < 10000)
        {
            ++nCycles;
            var time = t0 + TimeSpan.FromMilliseconds(nCycles * 1000 / Hz);
            var ttw = (int)((time - DateTime.Now).TotalMilliseconds);
            if (ttw >= 1)
                Thread.Sleep(ttw);
        }
        Console.WriteLine(nCycles);
    }
}
Achille
  • 111
  • 2
  • 3
    I say it again, `Thread.Sleep()` [does not have the accuracy](http://stackoverflow.com/questions/1303667/how-accurate-is-thread-sleeptimespan) for 666Hz. Whenever you use that function, you'll most likely get something between 10ms and 25ms. – Bobby Jan 08 '11 at 23:14