Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwitchToThread/Thread.Yield vs. Thread.Sleep(0) vs. Thead.Sleep(1)

People also ask

What is the difference between sleep () and yield () methods of a thread?

Sleep() causes the currently executing thread to sleep (temporarily cease execution). Yield() causes the currently executing thread object to temporarily pause and allow other threads to execute.

What does thread sleep 0 do in Java?

Sleep(0) gives up CPU only to threads with equal or higher priorities.

Does sleep yield thread?

The operating system selects the thread to yield to. Thread. Sleep(msec) blocks the current thread for the specified number of milliseconds.

What's thread sleep () in threading?

Definition. Suspends the current thread for the specified amount of time.


SpinWait is useful on hyperthreaded processors. With hyperthreading, multiple OS scheduled threads can be running on the same physical processor, sharing the processor resources. SpinWait indicates to the processor that you are not doing any useful work and that it should run code from a different logical CPU. As the name suggests, it is typically used when you are spinning.

Suppose you have code like:

while (!foo) {} // Spin until foo is set.

If this thread is running on a thread on a hyperthreaded processor, it is consuming processor resources that could be used for other threads running on the processor.

By changing to:

while (!foo) {Thread.SpinWait(1);} 

We are indicating to the CPU to give some resources to the other thread.

SpinWait does not affect OS scheduling of threads.

For your main questions about the "Ultimate Yield", it depends heavily on your situation - you won't be able to get a good answer without clarifying why you want a thread to yield. From my perspective, the best way to yield the processor is getting the thread to enter a wait state and only waking when there is work to do. Anything else is just wasting CPU time.


The article "How does Locks Lock" by Jeff Moser (http://www.moserware.com/2008/09/how-do-locks-lock.html) can give some inside about the mechanics of SpinWait. To cite the document:

What exactly is it doing? Looking at Rotor's clr/src/vm/comsynchronizable.cpp gives us the reality:

FCIMPL1(void, ThreadNative::SpinWait, int iterations) { WRAPPER_CONTRACT; STATIC_CONTRACT_SO_TOLERANT;

for(int i = 0; i < iterations; i++)
    YieldProcessor();

} FCIMPLEND

Further diving shows that "YieldProcessor" is this macro:

#define YieldProcessor() __asm { rep nop }

This is a "repeat no-op" assembly instruction. It's also known in the Intel instruction set manual as "PAUSE - Spin Loop Hint." This means that the CPU knows about the spin waiting that we're wanting to accomplish.

Related: http://msdn.microsoft.com/en-us/library/ms687419(VS.85).aspx http://www.moserware.com/2008/09/how-do-locks-lock.html#lockfn7


SpinWait is design to wait without yielding the current timeslice

It is designed for situations where you know you'll want to do something in a very short time so losing you timeslice will be excessive.

I was under the impression Thread.Yield(x) for any value of x < the thread quantum was equivalent, including zero though I have no benchmarks to that effect.


In addition to other answers, here are some profiling numbers.

(!) Don't take this profiling too seriously! Is made just to illustrate above answers in numbers and roughly compare magnitude of values.

static void Profile(Action func)
    {
        var sw = new Stopwatch();
        var beginTime = DateTime.Now;
        ulong count = 0;
        while (DateTime.Now.Subtract(beginTime).TotalSeconds < 5)
        {
            sw.Start();
            func();
            sw.Stop();
            count++;
        }
        Console.WriteLine($"Made {count} iterations in ~5s. Total sleep time {sw.ElapsedMilliseconds}[ms]. Mean time = {sw.ElapsedMilliseconds/(double) count} [ms]");
    }

        Profile(()=>Thread.Sleep(0));
        Profile(()=>Thread.Sleep(1));
        Profile(()=>Thread.Yield());
        Profile(()=>Thread.SpinWait(1));

The results of spinning loops for ~5s:

Function   | CPU % | Iters made |  Total sleep  | Invoke 
           |       |            |  time [ms]    | time [ms]
===================================================================== 
Sleep(0)   | 100 0 | 2318103    | 482           | 0.00020
Sleep(1)   |  6  0 | 4586       | 5456          | 1.08971 
Yield()    | 100 0 | 2495220    | 364           | 0.00010
SpinWait(1)| 100 0 | 2668745    | 81            | 0.00003

Made with Mono 4.2.3 x86_64