Answered by:
Thread.Sleep(1) sleeps for 15.6 ms
Question
-
How do I create a high frequency loop (e.g. 10kHz). I have the following pattern:
while (true) {// do some work here
// sleep until the next cycle
Thread.Sleep(1);
}
but instead of the expected 1kHz, this loop only cycles at 64Hz, i.e.
sleeps for 15.6ms instead of 1. The structure is efficient, e.g. if no work is done (as per example) then 1000 threads like this running simultaneously consumes no noticable CPU power (0%). Is there any other way to sleep for a real 1ms rather than 15?
Thread.Sleep(1);
For high frequency loops I can use
but this takes the CPU to 100% and the actual sleep interval is dependent on CPU speed rather than (real) time.
Thread.SpinWait()
What I am looking for is a way to have higher frequency loops, e.g. 10kHz, 20kHz, etc. but with the efficiency of the "sleep" pattern above, so that virtually no CPU cycles are used if no work is done (other than looping). Is there a way to do this from managed code?
Many thanks for any help.Friday, May 27, 2005 12:56 PM
Answers
-
The short answer is that it is not possible to provide the timing guarantees you are looking for on Windows. Real-time operating systems can make these promises, but Windows is not a real-time operating system.
In most hosting environments, CLR threads correspond to OS threads (at least while they are running). In this case the Thread.Sleep method corresponds to the Sleep API function who’s documentation does a better job of setting expectations:
“The Sleep function suspends the execution of the current thread for at least the specified interval.”
The Windows thread scheduler ensures that each thread (at least those with the same priority) will get a fair slice of CPU time to execute (usually around 20 milliseconds). The Sleep function relinquishes the remainder of the thread’s time slice and the thread will not be offered another time slice until the specified interval has passed. Of course it may take longer than the specified interval before the scheduler gets around to that thread again.
That being said, you can get a little closer to the precision you are after by raising the priority of the thread, but this is generally not a good thing to do since it will likely starve threads at lower priorities, especially given the loop you described.
Friday, May 27, 2005 4:19 PM
All replies
-
I am not sure if the .NET Framework is designed for providing that kind of accuracy. Its finally and intermediate language which is then JITed so, I wonder if it possible to provide the kind of accuracy that you are expecting.
I'd request someone from Microsoft to answer this.
Regards,
VikramFriday, May 27, 2005 2:46 PM -
The short answer is that it is not possible to provide the timing guarantees you are looking for on Windows. Real-time operating systems can make these promises, but Windows is not a real-time operating system.
In most hosting environments, CLR threads correspond to OS threads (at least while they are running). In this case the Thread.Sleep method corresponds to the Sleep API function who’s documentation does a better job of setting expectations:
“The Sleep function suspends the execution of the current thread for at least the specified interval.”
The Windows thread scheduler ensures that each thread (at least those with the same priority) will get a fair slice of CPU time to execute (usually around 20 milliseconds). The Sleep function relinquishes the remainder of the thread’s time slice and the thread will not be offered another time slice until the specified interval has passed. Of course it may take longer than the specified interval before the scheduler gets around to that thread again.
That being said, you can get a little closer to the precision you are after by raising the priority of the thread, but this is generally not a good thing to do since it will likely starve threads at lower priorities, especially given the loop you described.
Friday, May 27, 2005 4:19 PM -
The system clock only ticks 18.2 times per second and the system Sleep() function is sensitive to this. To get millisecond sleeps, you need to use the Multi-Media API calls.
Friday, May 27, 2005 8:01 PM -
Thank you for the info. I remember in the old days one could access the high frequency CPU timers directly and get sub microsecond accuracy but what I need is a managed solution so this won't do. I'll take a look at the multimedia API's and see where that takes me.
Nandor.Sunday, May 29, 2005 5:20 PM -
If anyone else is interested in achieving true 1ms sleeps rather than 15ms then take a look at the following link. It contains some sample code using the multimedia API's which does just that (I've tried it).
http://www.dotnet247.com/247reference/msgs/57/289291.aspx
Thanks again for the pointer.
Nandor.Monday, May 30, 2005 3:51 PM -
I just ran into the same issue trying to benchmark some sort algorithms. It's apparent that the system ticker runs at 64hz == 15.625 ms, as that is the smallest step in time I see reported by GetProcessTimes() for the process user time.
Sunday, August 26, 2007 7:56 AM -
For benchmarking, this should be a non-issue, since you cannot possibly have reliable benchmark values if the differences you measure are smaller than 15 ms, and you can easily let the benchmark execute 10 (or 100, or 1000...) times if timer resolution is the issue. Of course, reliable benchmarking is much harder than just running the same algorithm lots of times in a row, but that's a topic for another forum.
Also, for benchmarking in a managed environment,System.Diagnostics.Stopwatchis what you need, since it will use the high-resolution timer if one is available.Sunday, August 26, 2007 11:07 AM -
Or, the performance monitor class have high resolution timing available.
Sunday, August 26, 2007 9:05 PM -
I have also found this problem. It seems to still exist in Windows 7 too. I have also done some more searching on the subject and found some code that allows for having a 1 millisecond sleep, by using the Multimedia API. It basically comes down to making a call to timeBeginPeriod (of the MM API) and giving it a lower value. After this, all Thread.Sleep calls will have a higher resolution (defined by the value given to timeBeginPeriod).
After you're done, you can call timeEndPeriod to reset to the "normal" state.
Details can be found on my blog.
----- http://jepsonsblog.blogspot.com -----Tuesday, January 18, 2011 8:53 AM -
Sadly that is now just a link to webhosting firm (dotnet247).
Does the originally described code still exist somewhere available to the public?
Thursday, August 29, 2019 10:26 PM -
https://web.archive.org/web/20051125042113/http://www.dotnet247.com/247reference/msgs/57/289291.aspx or https://groups.google.com/d/topic/microsoft.public.dotnet.framework/JAVLQius2Hw/discussion. It was a thread with the subject "C# Thread.Sleep malfunction" in the microsoft.public.dotnet.framework newsgroup in September and October 2004.
Friday, September 6, 2019 5:41 PM