2009-06-23 15 views
5

Jaki jest najbardziej efektywny sposób monitorowania kolejki.Najbardziej efektywny sposób monitorowania kolejki

follwoing kawałek kodu jest największym wieprz zasobów:

/// <summary> 
/// Starts the service. 
/// </summary> 
private void StartService() 
{ 
    while (true) 
    { 
     //the check on count is not thread safe 
     while (_MessageQueue.Count > 0) 
     { 
      Common.IMessage message; 
      // the call to GetMessageFromQueue is thread safe 
      if (_MessageQueue.GetMessageFromQueue(out message) == true) 
      { 
       if (message.RoutingInfo == Devices.Common.MessageRoutingInfo.ToDevice) 
       { 
        _Port.SerialPort.WriteLine(message.Message); 
       } 
       if (message.RoutingInfo == Devices.Common.MessageRoutingInfo.FromDevice) 
       { 
        OnDeviceMessageReceived(new Common.DeviceMessageArgs(message.Message)); 
       } 
      } 
     } 
    } 
} 

start Usługa działa w wątku tła, wezwanie do _MessageQueue.Count nie jest wątku bezpieczne, nie jestem blokowania na licznik w kolejka komunikatów. Jednak blokuję implementację _MessageQueue.GetMessageFromQueue. Czy sposób, w jaki postępowałem tak skutecznie? Czy powinienem raczej podnieść zdarzenie Za każdym razem, gdy kolejka przechodzi od liczby 0 do większej od zera?

Odpowiedz

5

Powinieneś prawdopodobnie uwzględnić w tej metodzie jakiś rodzaj wątku, w przeciwnym razie będzie on wykorzystywać 100% procesora. Alternatywnie można utworzyć uchwyt oczekiwania i ustawić go po dodaniu wiadomości do kolejki.

+1

Nie śpi, chyba że masz żadnej kontroli nad producenta. Użyj zdarzeń lub sygnałów, aby wykonać odpowiednie oczekiwanie/powiadomienia. –

+0

Dlaczego Mats? Mam kontrolę nad producentem. Czy powinienem zgłaszać wydarzenie, gdy element zostanie dodany do kolejki? Zajrzę do waithandle. – AndyMM

+0

+1. Zobacz moją odpowiedź na przykład. – dtb

1

Czy _MessageQueue jest używany tylko z Twojego kodu? Następnie można owinąć go w klasie tak:

public class BlockingMessageQueue { 
    private readonly MyMessageQueue queue; 
    private readonly Semaphore signal; 

    public BlockingMessageQueue(MyMessageQueue queue) { 
    this.queue = queue; 
    this.signal = new Semaphore(0, int.MaxValue); 
    } 

    public void Enqueue(IMessage message) { 
    lock (this.queue) { 
     this.queue.Send(message); 
    } 
    this.signal.Release(); 
    } 

    public IMessage Dequeue() { 
    this.signal.WaitOne(); 
    IMessage message; 
    lock (this.queue) { 
     var success = this.queue.GetMessageFromQueue(out message); 
     Debug.Assert(success); 
    } 
    return message; 
    } 
} 

Dequeue zablokuje aż wiadomość jest dostępna, więc nie ma żadnych cykli zmarnowane, jeśli żadna wiadomość nie jest dostępna.

Przykład użycia:

var queue = new BlockingMessageQueue(_MessageQueue); 

while (true) { 
    var message = queue.Dequeue(); 

    if (message.RoutingInfo == Devices.Common.MessageRoutingInfo.ToDevice) 
    { 
    _Port.SerialPort.WriteLine(message.Message); 
    } 
    else if (message.RoutingInfo == Devices.Common.MessageRoutingInfo.FromDevice) 
    { 
    OnDeviceMessageReceived(new Common.DeviceMessageArgs(message.Message)); 
    } 
} 
+0

Dziękuję bardzo, na pewno dam to. Dam ci znać, jak to działa. Dzięki – AndyMM

Powiązane problemy