Thread.Sleep(1)是否特殊?

Joe Duffy( Windows上的Concurrent Programming的作者)在这篇博客文章中写道,Thread.Sleep(1)优于Thread.Sleep(0),因为它将挂起相同和更低优先级的线程,而不是像Thread 。睡眠(0)。

MSDN的.NET版本说 Thread.Sleep(0)是特殊的,它将挂起这个线程,并允许其他等待的线程执行。 但是它没有提及Thread.Sleep(1)(对于任何.NET版本)。

那么Thread.Sleep(1)实际上是在做什么特别的事情呢?

背景:

我正在刷新我对并发编程的知识。 我写了一些C#代码来清楚地显示前/后增量和减量是非primefaces的,因此不是线程安全的。

为了避免需要创build数百个线程,在递增共享variables之后放置一个Thread.Sleep(0)来强制调度器运行另一个线程。 线程的这种定期交换使得前/后递增/递减的非primefaces性更加明显。

Thread.Sleep(0)似乎不会导致额外的延迟,如预期的那样。 但是,如果我改变这个Thread.Sleep(1),它似乎恢复到正常的睡眠行为(例如,我得到大约至less1毫秒的延迟)。

这将意味着虽然T​​hread.Sleep(1)可能是首选,但是在循环中使用它的任何代码将运行得更慢。

这个问题“有人能解释这个有趣的睡眠行为(1)吗? 是相关的,但它是C ++的重点,只是在乔·达菲的博客文章重复的指导。

这里是我的代码感兴趣的人(从LinqPad复制,所以你可能需要添加一个类):

int x = 0; void Main() { List<Thread> threadList=new List<Thread>(); Stopwatch sw=new Stopwatch(); for(int i=0; i<20; i++) { threadList.Add(new Thread(Go)); threadList[i].Priority=ThreadPriority.Lowest; } sw.Start(); foreach (Thread thread in threadList) { thread.Start(); } foreach (Thread thread in threadList) { thread.Join(); } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); Thread.Sleep(200); Console.WriteLine(x); } void Go() { for(int i=0;i<10000;i++) { x++; Thread.Sleep(0); } } 

由于Microsoft更改了Windows API Sleep()的实现,因此不再需要使用Sleep(1)而不是Sleep(0) Sleep()

从睡眠()的MSDN文档 ,这是睡眠(0)现在发生的事情:

值为零将导致线程放弃其时间片的其余部分到准备运行的任何其他线程 。 如果没有其他线程准备运行,则该函数立即返回,线程继续执行。

这是以前在Windows XP中发生的事情:

值为零将导致线程将其时间片的其余部分放弃到准备运行的同等优先级的任何其他线程 。 如果没有其他相同优先级的线程准备运行,则该函数立即返回,线程继续执行。 此行为从Windows Server 2003开始更改。

请注意“任何其他线程”和“任何其他同等优先级的线程”之间的区别。

Joe Duffybuild议使用Sleep(1)而不是Sleep(0)的唯一原因是它是最短的Sleep()值,如果没有其他等待优先级的线程准备运行,将会阻止Sleep()立即返回,在Windows XP上运行时。

Windows Server 2003之后,由于Sleep()的行为发生变化,您不必担心操作系统版本。

我把你的注意力吸引到Joe的博客的这一部分:

即使有一个明确的睡眠在那里,发出它不允许生产者被安排,因为它在一个较低的优先级。

在XP中,即使主线程(更高优先级)执行了Sleep(0),优先级较低的线程也会处于饥饿状态。 在XP后,这将不再发生,因为睡眠(0)将允许较低优先级的线程运行。