Thread.sleep vs Monitor.Wait vs RegisteredWaitHandle?

Roy*_*mir 10 .net c# clr multithreading .net-4.0

(以下项目有不同的目标,但我很有趣,知道他们如何"PAUSEd")

问题

Thread.sleep - 它是否会影响系统的性能?是否会将线程与其等待相关联?

怎么样 Monitor.Wait ?他们"等待"的方式有什么不同?他们在等待时会占用一个线程吗?

怎么样RegisteredWaitHandle?此方法接受在发出等待句柄信号时执行的委托.在等待时,它不会占用一个线程.

所以一些线程被暂停并且可以被代表唤醒,而其他线程只是等待?旋转?

有人可以让事情更清楚吗?

编辑

http://www.albahari.com/threading/part2.aspx

在此输入图像描述

Tud*_*dor 8

双方Thread.SleepMonitor.Wait把线程WaitSleepJoin状态:

WaitSleepJoin:线程被阻止.这可能是调用Thread :: Sleep或Thread :: Join,请求锁定的结果 - 例如,通过调用Monitor :: Enter或Monitor :: Wait - 或等待线程同步对象(如ManualResetEvent).

RegisteredWaitHandle是通过调用RegisterWaitForSingleObject并传递一个WaitHandle.通常,此类的所有后代都使用阻塞机制,因此调用Wait将再次将线程放入WaitSleepJoin(例如AutoResetEvent).

这是MSDN的另一个引用:

RegisterWaitForSingleObject方法检查指定对象的WaitHandle的当前状态.如果对象的状态是无信号的,则该方法注册等待操作.等待操作由线程池中的线程执行.当对象的状态发出信号或超时间隔过去时,委托由工作线程执行.

所以池中的线程确实等待信号.


Joe*_*ari 6

关于ThreadPool.RegisterWaitForSingleObject,这并不会占用每注册(收集或以其他方式)的螺纹.您可以轻松地测试它:在LINQPad中运行以下脚本,该脚本调用该方法20,000次:

static ManualResetEvent _starter = new ManualResetEvent (false);

void Main()
{
    var regs = Enumerable.Range (0, 20000)
        .Select (_ => ThreadPool.RegisterWaitForSingleObject (_starter, Go, "Some Data", -1, true))
        .ToArray();

    Thread.Sleep (5000);
    Console.WriteLine ("Signaling worker...");
    _starter.Set();
    Console.ReadLine();

    foreach (var reg in regs) reg.Unregister (_starter);
}

public static void Go (object data, bool timedOut)
{
    Console.WriteLine ("Started - " + data);
    // Perform task...
}
Run Code Online (Sandbox Code Playgroud)

如果该代码在5秒"等待"的持续时间内捆绑了20,000个线程,则无法工作.

编辑 - 响应:

"这是一个证据.但是仍然有一个线程只在线程池中检查信号吗?"

这是一个实现细节.是的,它可以通过一个将回调卸载到托管线程池的线程来实现,尽管不能保证这一点.等待句柄最终由操作系统管理,这很可能也会触发回调.它可能在其内部实现中使用一个线程(或少量线程).或者使用中断,它可能不会阻止单个线程.它甚至可能根据操作系统版本而有所不同.这是一个与我们无关的实施细节.


Eli*_*bel 5

确实RegisterWaitForSingleObject会创建等待线程,但并非每个调用都会创建一个。

MSDN

需要时会自动创建新的等待线程

来自Raymond Chen的博客

...而不是花费整个线程,它花费的费用接近(但不完全是)线程的1/64

因此RegisterWaitForSingleObject,通常比使用您自己的等待线程更好。