Thread.Sleep(timeout)和ManualResetEvent.Wait(timeout)有什么区别?

Eri*_*bes 13 c# multithreading sleep timeout waithandle

Thread.Sleep(timeout)和resetEvent.Wait(timeout)都会导致执行暂停至少timeout几毫秒,那么它们之间是否存在差异?我知道Thread.Sleep导致线程放弃其时间片的剩余部分,因此可能导致睡眠持续时间远远超过要求的时间.ManualResetEvent对象的Wait(timeout)方法是否具有相同的问题?

编辑:我知道一个ManualResetEvent的主要要点是从另一个线程发出信号 - 现在我只关注事件的Wait方法的情况,指定了超时,没有其他调用者设置事件.我想知道是否比Thread.Sleep更准确地唤醒准时

zil*_*n01 24

Thread.Sleep(timeout)在恢复执行之前导致无条件等待.resetEvent.WaitOne(timeout)导致线程等待,直到(1)触发事件,或(2)达到超时.

使用事件的关键是从另一个线程触发它们,这样你就可以直接控制线程何时被唤醒.如果您不需要,则不应使用事件对象.

编辑:时间方面,他们都同样可靠.但是,你对"按时觉醒"的评论让我很担心.为什么需要按时唤醒代码?SleepWaitOne没有真正考虑到精确设计.

只有timeout在大约50ms左右并且您需要可靠性时,您应该研究其他的计时方法.这篇文章看起来非常好.


Mar*_*ers 8

Thread.Sleep和之间的主要区别在于ManualResetEvent.WaitOne,您可以使用Set方法向使用SetResetEvent等待的线程发出信号,从而导致线程在超时之前唤醒.

如果你没有发出信号,那么我希望它们的表现方式非常相似.

从.NET Reflector我可以看到该方法ManualResetEvent.WaitOne最终导致使用以下签名调用extern方法:

int WaitOneNative(SafeWaitHandle waitHandle,
                  uint millisecondsTimeout,
                  bool hasThreadAffinity,
                  bool exitContext);
Run Code Online (Sandbox Code Playgroud)

Thread.Sleep调用这种外部方法:

void SleepInternal(int millisecondsTimeout);
Run Code Online (Sandbox Code Playgroud)

不幸的是我没有这些方法的源代码,所以我只能猜测.我想,在两次调用中都会导致线程在等待超时时间之前被调度出来,而且两者都没有特别准确.


Rus*_*sty 7

对于延迟和周期,我发现Monitor.Wait是个不错的选择..

object timelock = new object();

lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); }
Run Code Online (Sandbox Code Playgroud)

这样可以获得出色的结果......〜1ms抖动或更好,具体取决于具体应用.

你可能已经知道Thread.Sleep(X)是不可靠的,不能取消....我像瘟疫一样避免它.


Han*_*ant 5

Sleep() 函数已经很长时间没有以这种方式工作了。它的准确性由多媒体计时器周期决定,您可以通过 P/Invoking timeBeginPeriod() 更改该周期。不幸的是,在我的机器上,我有某种程序可以将此周期设置为一毫秒,从而使睡眠精确到一毫秒。这里有一些代码供您自己尝试:

using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        //timeBeginPeriod(1);
        var sw1 = Stopwatch.StartNew();
        for (int ix = 0; ix < 100; ++ix) Thread.Sleep(10);
        sw1.Stop();
        var sw2 = Stopwatch.StartNew();
        var mre = new ManualResetEvent(false);
        for (int ix = 0; ix < 100; ++ix) mre.WaitOne(10);
        sw1.Stop();
        Console.WriteLine("Sleep: {0}, Wait: {1}", sw1.ElapsedMilliseconds, sw2.ElapsedMilliseconds);
        Console.ReadLine();
        //timeEndPeriod(1);
    }
    [DllImport("winmm.dll")]
    private static extern int timeBeginPeriod(int period);
    [DllImport("winmm.dll")]
    private static extern int timeEndPeriod(int period);
}
Run Code Online (Sandbox Code Playgroud)

我的机器上的输出:

睡眠:999,等待:1003

变化约为 5 毫秒。