Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I improve the resolution of Thread.Sleep?

Thread.Sleep() resolution varies from 1 to 15.6ms

Given this console app:

class Program
{
    static void Main()
    {
        int outer = 100;
        int inner = 100;
        Stopwatch sw = new Stopwatch();

        for (int j = 0; j < outer; j++)
        {
            int i;
            sw.Restart();
            for (i = 0; i < inner; i++)
                Thread.Sleep(1);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}

I expected the output to be 100 numbers close to 100. Instead, I get something like this:

99 99 99 100 99 99 99 106 106 99 99 99 100 100 99 99 99 99 101 99 99 99 99 99 101 99 99 99 99 101 99 99 99 100 99 99 99 99 99 103 99 99 99 99 100 99 99 99 99 813 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1559 1560 1559 1559 1559 1559 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1558 1559 1558 1558 1558 1558 1558

But sometimes I won't get any accurate results; it will be ~1559 every time.

Why isn't it consistent?

Some googling taught me that 15.6ms is the length of a timeslice, so that explains the ~1559 results. But why is it that I sometimes get the right result, and other times I just get a multiple of 15.6? (e.g. Thread.Sleep(20) will usually give ~31.2ms)

How is it affected by hardware or software?

I ask this because of what led me to discover it:

I had been developing my application on a 32 bit dual-core machine. Today my machine was upgraded to 64bit quad-core with a complete OS re-install. (Windows 7 and .NET 4 in both cases, however I can't be sure the older machine had W7 SP1; the new one does.)

Upon running my application on the new machine, I immediatey notice my forms take longer to fade out. I have a custom method to fade my forms which uses Thread.Sleep() with values varying from 10 to 50. On the old system this seemed to work perfectly every time. On the new system it's taking much longer to fade than it should.

Why did this bahavior change between my old system and my new system? Is this related to hardware, or software?

Can I make it consistently accurate? (~1ms resolution)

Is there something I can do in my program to make Thread.Sleep() reliably accurate to about 1ms? Or even 10ms?

like image 319
Igby Largeman Avatar asked Sep 30 '11 19:09

Igby Largeman


3 Answers

The answer is not to use Thread.Sleep and instead use a high resolution timer. You'll need to do your fade in a busy loop, but it sounds like that would be no problem. You simply cannot expect high resolution from Thread.Sleep and it is notorious for behaving differently on different hardware.

You can use the Stopwatch class on .net which uses high-resolution performance counters if they are supported on the hardware.

like image 96
David Heffernan Avatar answered Oct 21 '22 13:10

David Heffernan


“The Sleep function suspends the execution of the current thread for at least the specified interval.”

-> http://social.msdn.microsoft.com/Forums/en/clr/thread/facc2b57-9a27-4049-bb32-ef093fbf4c29

like image 35
MasterCassim Avatar answered Oct 21 '22 12:10

MasterCassim


I can answer one of my questions: Can I make it consistently accurate? (~1ms resolution)

Yes, it seems that I can, using timeBeginPeriod() and timeEndPeriod().

I've tested this and it works.

Some things I've read suggest that calling timeBeginPeriod(1) for the duration of the application is a bad idea. However, calling it at the start of a short method and then clearing it with timeEndPeriod() at the end of the method should be okay.

Nevertheless I will also investigate using timers.

like image 26
Igby Largeman Avatar answered Oct 21 '22 13:10

Igby Largeman