47

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

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

那么,Thread.Sleep(1) 真的做了什么特别的事情吗?

背景:

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

为了避免需要创建数百个线程,我在增加共享变量后放置了一个 Thread.Sleep(0) 以强制调度程序运行另一个线程。这种线程的定期交换使前/后递增/递减的非原子性质更加明显。

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

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

这个 SO 问题“有人可以用 Sleep(1) 解释这种有趣的行为吗?” 有点相关,但它以 C++ 为重点,只是重复了 Joe Duffy 博客文章中的指导。

这是我为感兴趣的人提供的代码(从 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);
    }
}
4

1 回答 1

59

你不再需要使用Sleep(1)代替,Sleep(0)因为微软改变了 Windows API 的实现Sleep()

Sleep() 的 MSDN 文档中,这就是 Sleep(0) 现在发生的情况:

零值会导致线程将其时间片的剩余部分交给任何其他准备运行的线程。如果没有其他线程准备好运行,则函数立即返回,线程继续执行。

这是在 Windows XP 中曾经发生的情况:

零值会导致线程将其时间片的剩余部分让给任何其他准备运行的具有相同优先级的线程。如果没有其他同等优先级的线程准备运行,则函数立即返回,线程继续执行。从 Windows Server 2003 开始​​,此行为发生了变化。

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

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

对于 Windows Server 2003 之后的操作系统版本,您无需担心这一点,因为 Sleep() 的行为发生了变化。

我提请您注意 Joe 博客的这一部分:

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

在 XP 中,即使(较高优先级的)主线程执行了 Sleep(0),较低优先级的线程也会被饿死。在 XP 之后,这将不再发生,因为 Sleep(0) 将允许较低优先级的线程运行。

于 2013-05-16T10:09:23.640 回答