2009-06-23 81 views
5

监控队列的最有效方式是什么?监控队列的最有效方式

的follwoing一段代码是资源最大的猪:

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

启动服务运行在后台线程调用_MessageQueue.Count不是线程安全的,我不是的MessageQueue锁定的计数。然而,我确实锁定了_MessageQueue.GetMessageFromQueue的实现。 我对这种高效率的方式有所了解吗?我是否应该提出一个事件每当队列从0计数到大于零时?

回答

5

您应该在该方法中包含某种类型的线程睡眠,否则将使用100%的CPU。或者,您可以创建一个等待句柄,并在将消息添加到队列时对其进行设置。

+1

不睡觉,除非你有过生产没有任何控制。使用事件或信号做适当的等待/通知。 – 2009-06-23 15:34:53

+0

为什么选择Mats?我控制着制片人。当一个项目被添加到队列中时,我应该提出一个事件吗?我会考虑等待处理。 – AndyMM 2009-06-23 15:49:25

1

_MessageQueue是否仅用于您的代码?然后,你可以在这样的类包起来:

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将阻塞,直到有可用消息,所以没有等待的周期,如果没有可用消息。

用例:

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