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

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

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

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

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

编辑:时间方面,他们都同样可靠。 但是,你对“按时觉醒”的评论让我很担心。 为什么需要按时唤醒代码? SleepWaitOne在设计时并没有精确设计。

只有当timeout低于50ms左右并且您需要可靠性时 ,您才应该研究其他的计时方法。 这篇文章看起来很不错。

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

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

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

 int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext); 

Thread.Sleep调用这个extern方法:

 void SleepInternal(int millisecondsTimeout); 

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

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

 object timelock = new object(); lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); } 

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

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

Sleep()函数很长时间没有这种方式。 它的准确性由多媒体计时器周期决定,你可以通过P / Invoking timeBeginPeriod()来改变它。 不幸的是,在我的机器上,我有一些程序可以将这段时间设置为1毫秒,使睡眠精确到毫秒。 这是一些自己尝试的代码:

 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); } 

我机器上的输出:

睡眠:999,等待:1003

可变性约为5毫秒。

正如其他人所提到的,不同之处在于,如果发出信号,WaitOne可能会在睡眠时间之前返回。 保证睡眠等待睡眠时间。

Thread.Sleep在reflection器调用中:

 [MethodImpl(MethodImplOptions.InternalCall)] private static extern void SleepInternal(int millisecondsTimeout); 

reflection器调用中的ManualResetEvent.Wait:

 private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext); 

不确定两者之间是否存在差异,但我会看是否能找到一些东西。

睡眠持续指定的时间。 如果发出事件信号,事件等待可以更快结束。 这是事件的目的:允许一个线程告诉另一个线程唤醒。

在一个post中你会说:

  mre.WaitOne(10000); // ten seconds Console.WriteLine("Woke up!"); 

在另一个你会说:

  mre.Set(); // this causes `WaitOne` to return in the first thread 

如果没有在另一个线程中调用Set ,第一个线程将有效地hibernate10秒。