2010-06-08 7 views
9

Thread.Sleep (timeout) et resetEvent.Wait (timeout) provoquent l'exécution d'une pause d'au moins timeout millisecondes, alors existe-t-il une différence entre eux? Je sais que Thread.Sleep amène le thread à abandonner le reste de sa tranche de temps, ce qui peut entraîner un sommeil qui dure beaucoup plus longtemps que prévu. Est-ce que la méthode Wait (timeout) d'un objet ManualResetEvent a le même problème?Quelle est la différence entre Thread.Sleep (timeout) et ManualResetEvent.Wait (timeout)?

Modifier: Je suis conscient que doit être signalé par un autre thread principal point d'un ManualResetEvent - en ce moment je suis seulement préoccupé par le cas de la méthode d'attente d'un événement avec une durée d'expiration, et pas d'autres appelants réglage l'événement. Je veux savoir si elle est plus fiable pour réveiller à temps que Thread.Sleep

Répondre

21

Thread.Sleep(timeout) provoque une attente inconditionnelle avant la reprise de l'exécution. resetEvent.WaitOne(timeout) oblige le thread à attendre que (1) l'événement soit déclenché ou (2) que le délai d'expiration soit atteint.

Le point d'utilisation des événements est de les déclencher à partir d'un autre thread, de sorte que vous pouvez contrôler directement quand le thread se réveille. Si vous n'en avez pas besoin, vous ne devriez pas utiliser d'objets événement.

EDIT: Dans le temps, ils sont tous deux également fiables. Cependant, votre commentaire sur "l'éveil à l'heure" m'inquiète. Pourquoi avez-vous besoin de votre code pour se réveiller à l'heure? Sleep et WaitOne ne sont pas vraiment conçus avec une grande précision.

Seulement si timeout est inférieure à 50ms ou plus et vous avez besoin de la fiabilité, vous devriez examiner d'autres méthodes de synchronisation. This article ressemble à un assez bon aperçu.

+0

Je le sais; Je ne suis vraiment intéressé que par le cas du timeout. Je veux savoir s'il est plus fiable de se réveiller à l'heure que Thread.Sleep –

+0

Thread.Sleep bloque-t-il les messages COM et les événements? Si nous devons retarder le thread principal pendant quelques secondes, ce qui devrait être utilisé Thread.Sleep ou WaitOne ??? – lerner1225

8

La principale différence entre Thread.Sleep et ManualResetEvent.WaitOne est que vous pouvez signaler à un thread en attente sur un ManualResetEvent en utilisant la méthode Set, ce qui provoque le fil de se réveiller plus tôt que le délai d'expiration.

Si vous ne signalez pas alors je m'attendrais à ce qu'ils se comportent d'une manière très similaire.

De .NET Reflector je peux voir que la méthode ManualResetEvent.WaitOne entraîne par la suite dans un appel à une méthode extern avec la signature suivante:

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

Attendu que Thread.Sleep appelle cette méthode extern:

void SleepInternal(int millisecondsTimeout); 

Malheureusement, je n'ai pas le code source pour ces méthodes, donc je ne peux que deviner. J'imagine que dans les deux appels, le thread est programmé à l'extérieur pendant qu'il attend l'expiration du délai, aucun n'étant plus précis que l'autre.

1

La mise en veille se poursuit pendant l'heure spécifiée. L'attente d'événement peut se terminer plus tôt si l'événement est signalé. C'est le but des événements: permettre à un thread de dire à un autre de se réveiller.

Dans un fil que vous diriez:

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

Dans un autre vous dirais:

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

Sans l'appel à Set dans l'autre fil, le premier fil dormirait efficacement 10 secondes.

1

Comme d'autres l'ont mentionné, la différence est que WaitOne pourrait revenir avant le temps de sommeil s'il est signalé. Le sommeil est garanti pour attendre le temps de sommeil.

Thread.Sleep dans les appels réflecteur:

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

ManualResetEvent.Wait dans les appels réflecteur:

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

Je ne sais pas s'il y a une différence entre les deux, mais je vais voir si je peut trouver quelque chose.

4

La fonction Sleep() n'a pas fonctionné de cette manière pendant longtemps. Sa précision est déterminée par la période de minuterie multimédia, quelque chose que vous pouvez changer en appelant/invoquant timeBeginPeriod(). Malheureusement, sur ma machine, j'ai une sorte de programme qui règle cette période à une milliseconde, ce qui rend les dortoirs précis jusqu'à une milliseconde. Voici un code pour essayer pour vous-même:

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

Sortie sur ma machine:

sommeil: 999, Attendez: 1003

avec une grande variabilité d'environ 5 millisecondes.

+0

Vous n'avez pas de références pour ça, n'est-ce pas? –

+0

Examinez les documents SDK pour Sleep() dans la bibliothèque MSDN. –

5

Pour les retards et Periodics j'ai trouvé Monitor.Wait un bon choix ..

object timelock = new object(); 

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

Cela donne un excellent résultat .... ~ de gigue 1ms ou mieux en fonction des spécificités de l'application.

Comme vous le savez peut-être Thread.Sleep (X) n'est pas fiable et ne peut pas être annulé .... Je l'évite comme la peste.

Questions connexes