Thread.Sleep(timeout)和resetEvent.Wait(timeout)导致执行暂停至少timeout
毫秒,那么它们之间有区别吗?我知道Thread.Sleep导致线程放弃其时间片的剩余部分,因此可能导致睡眠持续时间远远超过要求的时间。 ManualResetEvent对象的Wait(timeout)方法是否有同样的问题?
编辑:我知道要从另一个线程发出一个ManualResetEvent的主要信号 - 现在我只关注指定超时的事件Wait方法的情况,并且没有其他呼叫者设置该事件。我想知道是否比Thread.Sleep
更准确地唤醒准时答案 0 :(得分:21)
Thread.Sleep(timeout)
会导致无条件等待。 resetEvent.WaitOne(timeout)
导致线程等待,直到(1)触发事件,或(2)达到超时。
使用事件的目的是从另一个线程触发它们,这样你就可以直接控制线程何时被唤醒。如果您不需要,则不应使用事件对象。
编辑:时间方面,他们都同样可靠。但是,你对“按时觉醒”的评论让我很担心。为什么需要按时唤醒代码?Sleep
和WaitOne
并未真正考虑精确度。
仅当timeout
低于50毫秒且您需要可靠性时,您应该研究其他的计时方法。 This article看起来非常好。
答案 1 :(得分:8)
Thread.Sleep
和ManualResetEvent.WaitOne
之间的主要区别在于您可以使用Set方法向等待ManualResetEvent的线程发出信号,导致线程比超时更早地唤醒。
如果你没有发出信号,那么我希望它们的表现方式非常相似。
从.NET Reflector我可以看到方法ManualResetEvent.WaitOne
最终导致调用带有以下签名的extern方法:
int WaitOneNative(SafeWaitHandle waitHandle,
uint millisecondsTimeout,
bool hasThreadAffinity,
bool exitContext);
Thread.Sleep
调用此外部方法:
void SleepInternal(int millisecondsTimeout);
不幸的是我没有这些方法的源代码,所以我只能猜测。我想,在两次调用中都会导致线程在等待超时时间之前被调度出来,并没有比另一次更精确。
答案 2 :(得分:6)
对于延迟和周期,我发现Monitor.Wait是一个不错的选择..
object timelock = new object();
lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); }
这给出了一个很好的结果....〜1ms抖动或更好,具体取决于应用程序的具体情况。
你可能已经知道Thread.Sleep(X)是不可靠的,无法取消....我就像瘟疫一样避免它。
答案 3 :(得分:4)
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毫秒。
答案 4 :(得分:2)
正如其他人所提到的,不同之处在于,如果发出信号,WaitOne可能会在睡眠时间之前返回。保证睡眠等待睡眠时间。
反射器调用中的Thread.Sleep:
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void SleepInternal(int millisecondsTimeout);
反射器调用中的ManualResetEvent.Wait:
private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
不确定两者之间是否存在差异,但我会看是否能找到一些东西。
答案 5 :(得分:1)
睡眠持续指定的时间。如果发出事件信号,事件等待可以更快结束。这是事件的目的:允许一个线程告诉另一个线程唤醒。
在一个帖子中你会说:
mre.WaitOne(10000); // ten seconds
Console.WriteLine("Woke up!");
在另一个你会说:
mre.Set(); // this causes `WaitOne` to return in the first thread
如果没有在另一个线程中调用Set
,第一个线程将有效地休眠10秒。