What Is the Impact of Thread.Sleep(1) in C#

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 within n
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 than n milliseconds. The likelihood that your thread will
re-awaken exactly after n 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:

  1. We are waiting because we know a
    specific timespan when we should continue (use Thread.Sleep, System.Threading.Timer or alikes)

  2. 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



Leave a reply



Submit