2008-11-17 46 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