9 January 2011

Thread.Sleep(1) waits approx. 15 ms in stead of 1

Ever noticed how the time Thread.Sleep(int x) waits is not equal to x? I just noticed it happening with 2 threads with different values for the sleep, yet they were running just as quick.
After some research I discovered that the .Net runtime and Windows map this to a lower resolution in time, due to the way they handle threads. According to some sites it is 15.6 ms.
This means that any x between 1 and 15 will have your thread wait 15.6 ms (give or take, as it might be that your thread has to wait a bit more because of other calculations your CPU is processing). Any value between 16 and 31 will have your thread wait 2 x 15.6 ms (i.e. 31.2 ms) etc. The documentation also states that Thread.Sleep(int x) does not wait exactly x milliseconds, but rather "at least" x milliseconds.
For me, this is not a problem, I have just set the thread that was supposed to go slower to a different value, to make sure it actually runs slower. But just out of curiosity I have done some more research into how to solve it if you really want to have your thread sleep for a more precise period of time.
It seems the MultiMedia API's can help with that. I have tested the following code and it allowed me to set the sleep to a millisecond precisely.

[DllImport("winmm.dll")]internal static extern uint timeBeginPeriod(uint period);

[DllImport("winmm.dll")]
internal static extern uint timeEndPeriod(uint period);



{

Thread.Sleep(1); // waits roughly 15ms
Thread.Sleep(2); // waits roughly 15ms
Thread.Sleep(3); // waits roughly 15ms

timeBeginPeriod(1);

Thread.Sleep(1); // waits just over 1 ms
Thread.Sleep(2); // waits just over 2 ms
Thread.Sleep(3); // waits just over 3 ms

timeEndPeriod(1);

Thread.Sleep(1); // waits roughly 15ms
Thread.Sleep(2); // waits roughly 15ms
Thread.Sleep(3); // waits roughly 15ms

}

(this code was found here, posted by Per, so all credits go to him for this idea)


2 comments :

Anonymous said...

timeBeginPeriod() doesn't change the granularity of Sleep(), it reduces granularity of DateTime.Now from 15.6ms to 1ms.
Sleep() is fine and without timeBeginPeriod(), just use StopWatch instead of DateTime to measure...

Anonymous said...

Thanks, very good job... It works for me.