2009-06-23 40 views
5

¿Cuál es la forma más eficiente de monitorear una cola?Manera más eficiente de monitorear una cola

La pieza follwoing de código es el mayor de los recursos de cerdo:

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

Iniciar servicio se ejecuta en subproceso en segundo plano, la llamada a _MessageQueue.Count no es hilo de seguridad, no estoy de bloqueo en el recuento de MessageQueue. Sin embargo, bloqueo la implementación de _MessageQueue.GetMessageFromQueue. ¿Es esta la manera en que me he comportado de esta manera? ¿Debo plantear un evento cada vez que la cola pasa de un conteo de 0 a más de cero?

Respuesta

5

Probablemente deberías incluir algún tipo de suspensión de subprocesos en ese método, de lo contrario va a usar 100% de CPU. De forma alternativa, puede crear un identificador de espera y configurarlo cuando agrega un mensaje a la cola.

+1

No se duerme menos que usted no tiene control alguno sobre el productor. Use eventos o señales para hacer las esperas/notificaciones adecuadas. –

+0

¿Por qué esteras? Tengo control sobre el productor. ¿Debo plantear un evento cuando se agrega un artículo a la cola? Veré en el indicador de espera. – AndyMM

+0

+1. Ver mi respuesta para un ejemplo. – dtb

1

¿_MessageQueue solo se utiliza desde su código? Posteriormente, se podría envolver en una clase como esta:

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 bloqueará hasta que un mensaje está disponible, por lo que no hay ciclos desperdiciados si no hay mensaje está disponible.

Ejemplo de uso:

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

Muchas gracias, Definitivamente voy a intentarlo. Te dejaré saber cómo funciona. Gracias – AndyMM

Cuestiones relacionadas