2012-06-11 3 views
6

Ich benutze diesen Code und es ist eine Menge CPU, obwohl es die meiste Zeit absolut nichts tut.Wie blockiere ich einen Vorgang, bis eine Bedingung erfüllt ist?

while (this.IsListening) 
{ 
    while (this.RecievedMessageBuffer.Count > 0) 
    { 
     lock (this.RecievedMessageBuffer) 
     { 
      this.RecievedMessageBuffer[0].Reconstruct(); 
      this.RecievedMessageBuffer[0].HandleMessage(messageHandler); 
      this.RecievedMessageBuffer.RemoveAt(0); 
     } 
    } 
} 

Was ist der beste Weg zu blockieren, bis eine Bedingung erfüllt ist?

+4

'Thread.Sleep()'? –

+0

Thread.Sleep() blockiert auch die Benutzeroberfläche. –

+4

@RanhiruCooray nein, das ist fast immer die * falsche * Antwort. Es gibt Strukturen, die diesem Job gewidmet sind, wie der von Mark vorgeschlagene WaitHandle. Siehe http://stackoverflow.com/questions/9417260/when-is-it-sensible-to-use-thread-sleep –

Antwort

7

Angenommen, Sie verwenden .NET 4, würde ich vorschlagen, RecievedMessageBuffer zu einem BlockingCollection zu wechseln. Wenn Sie Nachrichten eingeben, rufen Sie die Methode Add auf. Wenn Sie eine Nachricht abrufen möchten, rufen Sie die Methode Take oder auf. Take wird den Lese-Thread blockieren, bis eine Nachricht verfügbar ist, ohne CPU wie das ursprüngliche Beispiel zu brennen.

// Somewhere else 
BlockingCollection<SomethingLikeAMessage> RecievedMessageBuffer = new BlockingCollection<SomethingLikeAMessage>(); 


// Something like this where your example was 
while (this.IsListening) 
{ 
    SomethingLikeAMessage message; 
    if (RecievedMessageBuffer.TryTake(out message, 5000); 
    { 
     message.Reconstruct(); 
     message.HandleMessage(messageHandler); 
    } 
} 
+1

Vielen Dank! das ist perfekt für das, was ich brauchte! Ich habe zuvor eine SyncronizedCollection <> verwendet, aber da BlockingCollection <> auch threadsicher ist, ist das perfekt für das, was ich mache! Alles läuft jetzt fantastisch glatt! – MJLaukala

9

Verwenden Sie eine WaitHandle.

Sie könnten auch erwägen, die Schnittstelle Ihrer Klasse zu ändern, um ein Ereignis auszulösen, wenn neue Daten gelesen werden sollen. Dann können Sie Ihren Code in den Event-Handler einfügen.

+0

Ich werde einige Tests mit WaitHandles durchführen müssen. Ich wusste vorher nie von ihnen. Niemals etwas zu ernst mit Multithreading vor ein paar Wochen gemacht. – MJLaukala

+0

Ich konnte 'WaitHandle' nicht mit' Set() 'Methode verwenden. Ich denke, es sollte mindestens 'EventWaitHandle' geben. – Gucu112

2

Oberhalb von Codezeilen und speziell AutoResetEvent ist in Version 3.5 verfügbar. So einfacher Code wie oben mit einigen kleinen Korrekturen ist sehr effektiv, weil es funktioniert und der Foundation API nah ist. Die Korrektur sollte

sein

AutoResetEvent waitHandle = neu AutoResetEvent (false); Konstruktor mit Argument false lässt WaitOne() warten, weil AutoResetEven nicht zurückgesetzt wird (false). Es gibt nicht viel Vorteil der Verwendung der Schnittstelle WaitHandle, also würde ich einfach AutoResetEvent verwenden, da es die Methode Set und WaitOne offen legt, ist in diesem Fall ziemlich ausführlich. Am wichtigsten ist, dass das Konstruktorargument und sollte falsch sein.