What is the impact of Thread.Sleep(1) in C#?
As stated, your loop will not hog the CPU.
But beware: Windows is not a real-time OS, so you will not get 1000 wakes per second from Thread.Sleep(1). If you haven't used timeBeginPeriod to set your minimum resolution you'll wake about every 15 ms. Even after you've set the minimum resolution to 1 ms, you'll still only wake up every 3-4 ms.
In order to get millisecond level timer granularity you have to use the Win32 multimedia timer (C# wrapper).
Purpose of Thread.Sleep(1)?
The 1
in that code is not terribly special; it will always end up sleeping longer than that, as things aren't so precise, and giving up your time slice does not equal any guarantee from the OS when you will get it back.
The purpose of the time parameter in Thread.Sleep()
is that your thread will yield for at least that amount of time, roughly.
So that code is just explicitly giving up its time slot. Generally speaking, such a bit of code should not be needed, as the OS will manage your threads for you, preemptively interrupting them to work on other threads.
This kind of code is often used in "threading examples", where the writer wants to force some artificial occurrence to prove some race condition, or the like (that appears to be the case in your example)
As noted in Jon Hanna's answer to this same question, there is a subtle but important difference between Sleep(0)
and Sleep(1)
(or any other non-zero number), and as ChrisF alludes to, this can be important in some threading situations.
Both of those involve thread priorities; Threads can be given higher/lower priorities, such that lower priority threads will never execute as long as there are higher priority threads that have any work to do. In such a case, Sleep(1)
can be required... However...
Low-priority threads are also subject to what other processes are doing on the same system; so while your process might have no higher-priority threads running, if any others do, yours still won't run.
This isn't usually something you ever need to worry about, though; the default priority is the 'normal' priority, and under most circumstances, you should not change it. Raising or lowering it has numerous implications.
Why there is a Thread.Sleep(1) in .NET internal Hashtable?
Sleep(1) is a documented way in Windows to yield the processor and allow other threads to run. You can find this code in the Reference Source with comments:
// Our memory model guarantee if we pick up the change in bucket from another processor,
// we will see the 'isWriterProgress' flag to be true or 'version' is changed in the reader.
//
int spinCount = 0;
do {
// this is violate read, following memory accesses can not be moved ahead of it.
currentversion = version;
b = lbuckets[bucketNumber];
// The contention between reader and writer shouldn't happen frequently.
// But just in case this will burn CPU, yield the control of CPU if we spinned a few times.
// 8 is just a random number I pick.
if( (++spinCount) % 8 == 0 ) {
Thread.Sleep(1); // 1 means we are yeilding control to all threads, including low-priority ones.
}
} while ( isWriterInProgress || (currentversion != version) );
The isWriterInProgress variable is a volatile bool. The author had some trouble with English "violate read" is "volatile read". The basic idea is try to avoid yielding, thread context switches are very expensive, with some hope that the writer gets done quickly. If that doesn't pan out then explicitly yield to avoid burning cpu. This would probably have been written with Spinlock today but Hashtable is very old. As are the assumptions about the memory model.
Is the precision of Thread.Sleep still poor?
The precision of Thread.Sleep
(and the underlying Windows API Sleep
function in kernel32) is dependent on the resolution of the system clock, which has a default tick rate of roughly 15 ms. Applications can request a higher resolution, in which case the highest requested resolution is used globally.
In this case case, you're likely seeing sub-15 ms resolution because something running on your system has requested a higher resolution.
If your application actually needs sub-15 ms sleeps, it can request a higher resolution via the native timeBeginPeriod function.
However, note that it is possible that the underlying timer device won't support your requested resolution, so it's not good practice to write code that relies on this behavior unless you're absolutely sure of the hardware your code will be running on.
Thread.Sleep(1) takes longer than 1ms
Timers other than Stopwatch are incremented by the clock interrupt. Which by default ticks 64 times per second on Windows. Or 15.625 milliseconds. So a Thread.Sleep() argument less than 16 doesn't give you the delay you are looking for, you'll always get at least that 15.625 interval. Similarly, if you read, say, Environment.TickCount or DateTime.Now and wait less than 16 millisecond then you'll read the same value back and think 0 msec has passed.
Always use Stopwatch for small increment measurements, it uses a different frequency source. Its resolution is variable, it depends on the chipset on the motherboard. But you can rely on it being better than a microsecond. Stopwatch.Frequency gives you the rate.
The clock interrupt rate can be changed, you have to pinvoke timeBeginPeriod(). That can get you down to a single millisecond and actually make Thread.Sleep(1) accurate. Best not to do this, it is very power unfriendly.
Why is Thread.Sleep so harmful
The problems with calling Thread.Sleep
are explained quite succinctly here:
Thread.Sleep
has its use: simulating lengthy operations while testing/debugging on an MTA thread. In .NET there's no other reason to use it.
Thread.Sleep(n)
means block the current thread for at least the number
of timeslices (or thread quantums) that can occur withinn
milliseconds.
The length of a timeslice is different on different versions/types of
Windows and different processors and generally ranges from 15 to 30
milliseconds. This means the thread is almost guaranteed to block for
more thann
milliseconds. The likelihood that your thread will
re-awaken exactly aftern
milliseconds is about as impossible as
impossible can be. So,Thread.Sleep
is pointless for timing.Threads are a limited resource, they take approximately 200,000 cycles
to create and about 100,000 cycles to destroy. By default they
reserve 1 megabyte of virtual memory for its stack and use 2,000-8,000
cycles for each context switch. This makes any waiting thread a
huge waste.
The preferred solution: WaitHandles
The most-made-mistake is using Thread.Sleep
with a while-construct (demo and answer, nice blog-entry)
EDIT:
I would like to enhance my answer:
We have 2 different use-cases:
We are waiting because we know a
specific timespan when we should continue (useThread.Sleep
,System.Threading.Timer
or alikes)We are waiting because some condition changes some time ...
keyword(s) is/are some time! if the condition-check is in our code-domain, we
should use WaitHandles - otherwise the external component should
provide some kind of hooks ... if it doesn't its design is bad!My answer mainly covers use-case 2
Impact of Thread.Sleep() in a continuous loop
It is far from optimal, wasting a Thread .
You should consider using a Timer or a WaitHandle or something. Without more details it's not possible to be precise.
But your current approach is not disastrous or anything, provided that that other thread uses lock
or InterLocked
to change the counter.
Thread.Sleep(0) vs Thread.Sleep(1) vs Thread.Sleep(2)
Thread.Sleep(n); // Where n is milliseconds
When N==0
This tells the system you want to forfeit the rest of the thread’s timeslice and let another waiting thread (whose priority >= currentThread) run (this means you won't be sure when you get your control back).
If there are no other threads of equal priority that are ready to run, execution of the current thread is not suspended.
When N>=1 (be it N=1 or N=2)
Will block the current thread for at least the number of timeslices (or thread quantums) that can occur within n milliseconds, In other words it will relinquish the remainder of its time slice to any other thread un-conditionally.
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. The reason for blocking the current thread for atleast specified interval is because scheduler might take longer than the specified interval before it gets around to that thread again.
References: 1, 2, 3
Update
In my pursuit to find the working of Sleep in versions prior to C# 3, I've come across interesting articles (on and before year 2005) that I felt is worth an update.
In short, I did not find any difference with regards to threads relinquishing to higher or same priority when n=1 or n=2.
From Vaults: 1, 2, 3
Thread.Sleep x Task.Delay
They do quite different things.
Thread.Sleep
causes the currently executing thread to just stop running for a given amount of time. It probably doesn't consume additional memory or do much processing, but the entire time it is sleeping it uses a system Thread, which is a limited resource. You could starve your application of threads, or cause another Thread to be created elsewhere, which has big performance impact. But, works great if that one thread is the only thing running on your computer.
Task.Delay
creates a Task that will be dormant for the given amount of time and then finish. If you use in an asynchronous method, this allows you to return the thread to the caller, which can use it for something else until the timer is up. This is much more efficient when you have multiple threads, such as in a web server environment or doing a lot of database reads. However, you must use await
, otherwise the task is created but then ignored, so it doesn't delay anything. And to use await, you must be in an asynchronous method in an asynchronous stack. You could call Wait()
on the task, but that still locks the thread so might as well use Sleep
at that point.
It looks like you have some worker threads of some kind. Better to make those tasks and they use .WaitAll
on WhenAll
or WhenAny
to wait until one is actually finished.
Related Topics
Declaration Suffix for Decimal Type
Populate Data Table from Data Reader
How to Bring My Application Window to the Front
Built in .Net Algorithm to Round Value to the Nearest 10 Interval
How to Split a String by Strings and Include the Delimiters Using .Net
What Does It Mean for a Property to Be [Required] and Nullable
What Does the Word "Literal" Mean
Differencebetween Bool and Boolean Types in C#
How to Read Data from a Zip File Without Having to Unzip the Entire File
What Requirement Was the Tuple Designed to Solve
What Is the Real Overhead of Try/Catch in C#
.Net Core 2.2 Can't Be Selected in Visual Studio Build Framework
How to Bind Datatable to Datagrid