2009-06-23 14 views
5

Was ist der effizienteste Weg, um eine Warteschlange zu überwachen.Der effizienteste Weg, um eine Warteschlange zu überwachen

Das follwoing Stück Code das größte Schwein von Ressourcen:

/// <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 Service auf Hintergrund-Thread ausgeführt wird, wird der Anruf an _MessageQueue.Count nicht Thread-sicher, ich bin Verriegelung nicht Zählung in Message auf. Ich sperre jedoch die Implementierung von _MessageQueue.GetMessageFromQueue. Bin ich so effizient gegangen? Soll ich eher ein Ereignis auslösen, wenn die Warteschlange von einer Zählung von 0 auf eine größere als Null geht?

Antwort

5

Sie sollten wahrscheinlich eine Art von Thread Schlaf in diese Methode einschließen, sonst wird es 100% CPU verwenden. Alternativ können Sie ein Wait-Handle erstellen und festlegen, wenn Sie der Warteschlange eine Nachricht hinzufügen.

+1

Nein schläft, wenn Sie keinerlei Kontrolle über den Hersteller haben. Verwenden Sie Ereignisse oder Signale, um ordnungsgemäße Wartungen/Benachrichtigungen durchzuführen. –

+0

Warum Matten? Ich habe die Kontrolle über den Produzenten. Sollte ich ein Ereignis auslösen, wenn ein Element zur Warteschlange hinzugefügt wird? Ich werde in Waithandle schauen. – AndyMM

+0

+1. Siehe meine Antwort für ein Beispiel. – dtb

1

Wird _MessageQueue nur von Ihrem Code verwendet? Dann könnte man es in einer Klasse wie folgt wickeln:

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 blockiert, bis eine Nachricht verfügbar ist, so gibt es keine verschwendeten Zyklen, wenn keine Nachricht verfügbar ist.

Anwendungsbeispiel:

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

Vielen Dank, ich werde es auf jeden Fall versuchen. Ich werde dich wissen lassen, wie es funktioniert. Vielen Dank – AndyMM

Verwandte Themen