views:

290

answers:

6

Both Thread.Sleep(timeout) and resetEvent.Wait(timeout) cause execution to pause for at least timeout milliseconds, so is there a difference between them? I know that Thread.Sleep causes the thread to give up the remainder of its time slice, thus possibly resulting in a sleep that lasts far longer than asked for. Does the Wait(timeout) method of a ManualResetEvent object have the same problem?

Edit: I'm aware that a ManualResetEvent's main point is to be signaled from another thread - right now I'm only concerned with the case of an event's Wait method with a timeout specified, and no other callers setting the event. I want to know whether it's more reliable to awaken on-time than Thread.Sleep

+2  A: 

The main difference between Thread.Sleep and ManualResetEvent.WaitOne is that you can signal to a thread waiting on a ManualResetEvent using the Set method, causing the thread to wake up earlier than the timeout.

If you don't signal then I would expect them to behave in a very similar way.

From .NET Reflector I can see that the method ManualResetEvent.WaitOne eventually results in a call to an extern method with the following signature:

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

Whereas Thread.Sleep calls this extern method:

void SleepInternal(int millisecondsTimeout);

Unfortunately I don't have the source code for these methods, so I can only guess. I'd imagine that in both calls result in the thread getting scheduled out while it is waiting for the time out to expire, with neither being particularly more accurate than the other.

Mark Byers
+4  A: 

Thread.Sleep(timeout) causes an unconditional wait before execution is resumed. resetEvent.WaitOne(timeout) causes the thread to wait until either (1) the event is triggered, or (2) the timeout is reached.

The point of using events is to trigger them from another thread, so you can directly control when the thread wakes up. If you don't need this, you shouldn't be using event objects.

EDIT: Timing-wise, they are both equally reliable. However, your comment about "awakening on time" worries me. Why do you need your code to wake up on time? Sleep and WaitOne aren't really designed with precision in mind.

Only if timeout is below 50ms or so and you need the reliability, you should look into alternate methods of timing. This article looks like a pretty good overview.

zildjohn01
I know that; I'm really only interested in the timeout case. I want to know whether it's more reliable to awaken on-time than Thread.Sleep
Erik Forbes
+1  A: 

The Sleep continues for the specified time. The event wait can end sooner if the event is signalled. This is the purpose of events: to allow one thread to tell another to wake up.

In one thread you'd say:

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

In another you'd say:

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

Without the call to Set in the other thread, the first thread would effectively sleep for 10 seconds.

Daniel Earwicker
+1  A: 

As others have mentioned, the difference is WaitOne could return before the sleep time if signaled. Sleep is guaranteed to wait for the sleep time.

Thread.Sleep in reflector calls:

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

ManualResetEvent.Wait in reflector calls:

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

Not sure if there is a difference between the two, but I'll see if I can find something.

SwDevMan81
+1  A: 

The Sleep() function hasn't worked this way for a long time. Its accuracy is determined by the multimedia timer period, something you can change by P/Invoking timeBeginPeriod(). Unfortunately, on my machine I've got some kind of program that sets this period to one millisecond, making sleeps accurate down to a millisecond. Here's some code to try for yourself:

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

Output on my machine:

Sleep: 999, Wait: 1003

with a variability of about 5 milliseconds.

Hans Passant
You don't happen to have any references for that, do you?
Erik Forbes
Look at the SDK docs for Sleep() in the MSDN library.
Hans Passant
+1  A: 

For delays and periodics I have found Monitor.Wait a good choice..

object timelock = new object();

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

This gives a excellent result....~1ms jitter or better depending on application specifics.

As you may already know Thread.Sleep(X) is unreliable and cannot be canceled....I avoid it like the plague.

Rusty