2008-11-17 51 views
2

我有一个生产者 - 消费者模式为一个产品工作。当生产者生产许多产品时,最好的实施是什么?例如,消费者应该使用的DataBaseEvent,GuiEvent和ControlEvent。下面的代码显示了一个产品的模式(一个DataBaseEvent)。应该将每个事件类型排入队列中,还是应该继承可以排队的基类。在处理很多事件类型时,可能存在更好的模式?生产者消费者模式,当很多产品

class DataBaseEventArgs : EventArgs 
{ 
    public string textToDB = ""; 
} 

class Consumer 
{ 
    private Producer mProducer = new Producer(); 
    private Queue<DataBaseEventArgs> mDataBaseEventQueue = new Queue<DataBaseEventArgs>(); 
    private static EventWaitHandle mDataBaseEventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); 
    private Thread mDataBaseEventDequeueThread = null; 

    public Consumer() 
    { 
     mDataBaseEventDequeueThread = new Thread(DataBaseDequeueEvent); 
     mDataBaseEventDequeueThread.Start(); 
     mProducer.mDataBaseEventHandler += WhenDataBaseEvent; 
    } 

    protected void DataBaseDequeueEvent() 
    { 
     while (true) 
     { 
      DataBaseEventArgs e; 
      lock (((ICollection)mDataBaseEventQueue).SyncRoot) 
      { 
       if (mDataBaseEventQueue.Count > 0) 
       { 
        e = mDataBaseEventQueue.Dequeue(); 
       } 
      } 
      // WriteToDatabase(e.textToDB); 
      if (mDataBaseEventQueue.Count == 0) 
      { 
       mDataBaseEventWaitHandle.WaitOne(1000); 
       mDataBaseEventWaitHandle.Reset(); 
      } 
     } 
    } 

    internal void WhenDataBaseEvent(object sender, DataBaseEventArgs e) 
    { 
     lock (((ICollection)mDataBaseEventQueue).SyncRoot) 
     { 
      mDataBaseEventQueue.Enqueue(e); 
      mDataBaseEventWaitHandle.Set(); 
     } 
    } 
} 

class Producer 
{ 
    public event EventHandler<DataBaseEventArgs> mDataBaseEventHandler = null; 

    public void SendDataBaseEvent() 
    { 
     if (mDataBaseEventHandler != null) 
     { 
      DataBaseEventArgs e = new DataBaseEventArgs(); 
      e.textToDB = "This text will be written to DB"; 
      mDataBaseEventHandler(this, e); 
     } 
    } 
} 

回答

0

我认为这将是更好的入队所有的请求到一个队列,如果它们具有相同的优先级,并会在类似的方式来处理。

如果其中一个请求的概率较高,那么您要么需要一些特殊的优先级队列,要么可以使用不同的队列。另外,如果以不同的方式处理消息,那么就没有必要过分复杂化模式。

4

如果您想积极分离工作 - 即为不同类型的事件分配不同的线程/池,那么多个队列将非常有用。如果你想共享负载,还有另一种选择 - 使用接口(而不是基类)。基类很好,但我想不出任何会通过接口强制实现基类的任何事情。甚至只是工作的一个代表!

另外 - 我不知道你在这种情况下需要重置事件;你可以经常只用锁和Monitor.Pulse/Wait来处理生产者/消费者(由于没有涉及OS对象 - 管理对象,所以开销较小)。然而,如果代码是目前最稳定的,或许离开“原样” - 线程是足够很难得到正确一次,更不用说两次......

但供参考,这将是这样的:

while(true) { 
    T item; 
    lock(lockObj) { 
     if(queue.Count == 0) { // empty 
      Monitor.Wait(lockObj); 
      continue; // ensure there is genuinely something to do 
     } 
     item = queue.Dequeue(); 
    } 
    // TODO: process item 
} 
... 
void Add(T item) { 
    lock(lockObj) { 
     queue.Enqueue(item); 
     if(queue.Count == 1) { // first 
      Monitor.PulseAll(lockObj); 
     } 
    } 
} 

(并记住要清理队列时PulseAll)

+0

感谢您的监视器代码示例。我认为我会使用它来代替EventWaitHandler。 – humcfc 2008-11-17 13:39:17