Thread.Sleep(1)是否特别?

本文关键字:是否 Sleep Thread | 更新日期: 2023-09-27 18:13:47

Joe Duffy (Windows上并发编程的作者)在这篇博客文章中写道,Thread.Sleep(1)比Thread.Sleep(0)更可取,因为它会挂起相同优先级和较低优先级的线程,而不像Thread.Sleep(0)那样只挂起同等优先级的线程。

. net版本的MSDN说thread . sleep(0)是特殊的,它会挂起这个线程并允许其他等待的线程执行。但是它没有提到Thread.Sleep(1)(适用于任何。net版本)。

那么,Thread.Sleep(1)实际上做了什么特别的事情吗?背景:

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

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

如预期的那样,

Thread.Sleep(0)似乎没有引起额外的延迟。然而,如果我将其更改为Thread.Sleep(1),它似乎恢复到正常的睡眠行为(例如:我得到的最小延迟大约是1ms)。

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

这个问题"有人能解释一下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);
    }
}

Thread.Sleep(1)是否特别?

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

从Sleep()的MSDN文档中,下面是Sleep(0)现在的情况:

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

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

如果值为0,则线程放弃剩余的时间片给其他具有相同优先级且准备运行的线程。如果没有其他具有同等优先级的线程准备运行,则该函数立即返回,线程继续执行。此行为从Windows Server 2003开始改变。

注意"任意其他线程"answers"任意其他同等优先级的线程"的区别。

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

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

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

即使这里有一个显式的Sleep,发出它也不允许生产者被调度,因为它的优先级较低。

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