2010-06-08 26 views
9

Ambos Thread.Sleep (timeout) y resetEvent.Wait (timeout) hacen que la ejecución se detenga durante al menos timeout milisegundos, entonces ¿hay alguna diferencia entre ellos? Sé que Thread.Sleep hace que el hilo abandone el resto de su división de tiempo, lo que posiblemente da como resultado un sueño que dura mucho más de lo que se solicita. ¿El método Wait (timeout) de un objeto ManualResetEvent tiene el mismo problema?¿Cuál es la diferencia entre Thread.Sleep (timeout) y ManualResetEvent.Wait (timeout)?

Editar: Soy consciente de que el punto principal de un ManualResetEvent debe ser señalado desde otro hilo - en este momento sólo estoy preocupado por el caso del método de espera de un evento con un tiempo de espera especificado, y el establecimiento de ningún otro llamadores el evento. Quiero saber si es más fiable para despertar a tiempo de Thread.Sleep

Respuesta

21

Thread.Sleep(timeout) provoca una espera incondicional antes de que se reanude la ejecución. resetEvent.WaitOne(timeout) hace que el hilo espere hasta que (1) se desencadene el evento o (2) se alcance el tiempo de espera.

El objetivo de usar eventos es desencadenarlos desde otro hilo, para que pueda controlar directamente cuando el hilo se despierta. Si no necesita esto, no debe usar objetos de evento.

EDITAR: Por el momento, ambos son igualmente confiables. Sin embargo, tu comentario sobre "despertar a tiempo" me preocupa. ¿Por qué necesitas que tu código se active a tiempo? Sleep y WaitOne no están realmente diseñados con precisión en mente.

Solo si timeout tiene menos de 50 ms o menos y necesita la confiabilidad, debe buscar métodos alternativos de sincronización. This article parece una muy buena visión general.

+0

Sé que; Solo estoy interesado en el caso del tiempo de espera. Quiero saber si es más fiable para despertar a tiempo de Thread.Sleep –

+0

Does Thread.Sleep bloquear los mensajes y eventos COM? Si tenemos que retrasar el hilo principal durante unos segundos, ¿cuál debería usarse Thread.Sleep o WaitOne ??? – lerner1225

8

La principal diferencia entre Thread.Sleep y ManualResetEvent.WaitOne es que se puede señalar a un hilo que espera en un ManualResetEvent utilizando el método Set, haciendo que el hilo de despertar hasta antes que el tiempo de espera.

Si no lo hace, entonces esperaría que se comportaran de manera similar.

De .NET Reflector puedo ver que el método ManualResetEvent.WaitOne eventualmente resulta en una llamada a un método externo con la siguiente firma:

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

Mientras que Thread.Sleep llama a este método extern:

void SleepInternal(int millisecondsTimeout); 

Lamentablemente, no tengo el código fuente para estos métodos, así que solo puedo adivinar. Me imagino que en ambas llamadas el hilo se programará mientras espera a que expire el tiempo de espera, sin que ninguno sea más preciso que el otro.

1

La suspensión continúa durante el tiempo especificado. La espera del evento puede finalizar antes si se señala el evento. Este es el propósito de los eventos: permitir que un hilo le diga a otro que se despierte.

En un hilo que diría:

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

En otro que diría:

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

Sin la llamada a Set en el otro hilo, el primer hilo dormiría con eficacia para 10 segundos.

1

Como otros han mencionado, la diferencia se WaitOne podría volver antes de que el tiempo de sueño si señalado. El sueño está garantizado para esperar el tiempo de sueño.

Thread.Sleep en llamadas de reflector:

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

ManualResetEvent.Wait en llamadas de reflector:

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

No estoy seguro si hay una diferencia entre los dos, pero voy a ver si me puede encontrar algo función

4

El Sleep() no ha funcionado de esta manera durante mucho tiempo. Su exactitud está determinada por el período del temporizador multimedia, algo que puede cambiar por P/Invocando timeBeginPeriod(). Por desgracia, en mi máquina tengo algún tipo de programa que establece este periodo de un milisegundo, la toma duerme cuidadas en una milésima de segundo. Aquí hay algo de código para probar por ti mismo:

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

salida en mi máquina:

sueño: 999, Espera: 1003

con una variabilidad de unos 5 milisegundos.

+0

No tiene ninguna referencia para eso, ¿verdad? –

+0

Mire los documentos SDK para Sleep() en la biblioteca de MSDN. –

5

Por retrasos y datos periódicos que he encontrado Monitor.Wait una buena opción ..

object timelock = new object(); 

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

Esto da un resultado excelente .... ~ 1 ms jitter o mejor en función de aspectos específicos de la aplicación.

Como usted ya sabe Thread.Sleep (X) no es fiable y no se puede cancelar .... Me evitar como la peste.