2011-04-30 47 views
2

我不明白這個例子如何工作http://msdn.microsoft.com/en-us/library/yy12yx1f(v=vs.80).aspx生產者/消費者msdn示例如何工作?

據我瞭解消費者不讀取由生產者生產的所有元素。 可能我不明白AutoResetEvent是如何工作的。 SetAutoreResetEvent幾次有意義嗎?

_newItemEvent = new AutoResetEvent(false); 
    _newItemEvent.Set(); 
    _newItemEvent.Set(); 
    _newItemEvent.Set(); 
    _newItemEvent.Set(); 

這就是我所理解的例子:

監製:

 lock (((ICollection)_queue).SyncRoot) 
     { 
      while (_queue.Count < 20) 
      { 
       _queue.Enqueue(r.Next(0,100)); 
       _syncEvents.NewItemEvent.Set(); 
       count++; 
      } 
     } 

消費者:

while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1) 
    { 
     lock (((ICollection)_queue).SyncRoot) 
     { 
      int item = _queue.Dequeue(); 
     } 
     count++; 
    } 
  1. 監製鎖_queue

     lock (((ICollection)_queue).SyncRoot) 
    
  2. 生產者增加1元到_queue,並設置NewItemEvent

     _queue.Enqueue(r.Next(0,100)); 
         _syncEvents.NewItemEvent.Set(); 
    
  3. 消費者走了進去「而」循環,因爲它是NewItemEvent設置收到通知,NetItemEvent是取消設置,因爲它的AutoResetEvent:

     while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1) 
    
  4. 消費者「凍結」在下一行等待_queue鎖ŧ ø被釋放:

     lock (((ICollection)_queue).SyncRoot) 
    
  5. 生產者繼續添加19個以上的元素到_quere和釋放_queue對象

  6. 消費者獲得_queue對象和Dequeue一種元素的鎖:

    lock (((ICollection)_queue).SyncRoot) 
        { 
         int item = _queue.Dequeue(); 
        } 
    
  7. 消費者執行「while」循環的第二次迭代,因爲NewItemEvent已設置,因此現在未設置NetItemEvent,因爲它是AutoRes etEv​​ent:

  8. 2次迭代後消費者等待NewItemEvent設置。

結果:生產者生產20個要素。 消費者:Dequeue只有2個元素。

我期望消費者可以通過Dequeue全部20個元素。

根據消費者的一個例子20個要素,問題是如何,爲什麼以及在我對程序的理解上出現了什麼問題。

回答

2

您在MSDN頁面上忽略了示例的重要部分,這是生產者線程中主環路的另一個循環。在這個例子中,生產者的工作是試圖在隊列中保留至少20個項目。

每當它添加一個項目時,消費者都會發出信號,導致它刪除一個項目,因此隊列中的項目少於20個。這是否在生產者線程的內部循環內部或外部發生並不重要。下一次它到達while (_queue.Count < 20)它將是錯誤的,所以生產者將至少再添加一個項目到隊列中,並且向消費者重新發信號。

不可否認,在我看來,至少就像一個有點人爲的例子,因爲消費者不一定會消耗隊列中的所有條目,但只要生產者繼續生產,它就會繼續消耗物品。

0

生產者入列20個元件 消費者消耗單個元件,通過一個減小了隊列現在隊列計數是19 現在的生產者入列1個元件隊列是在20 消費者消耗單個元件,降低了隊列爲1,現在隊列數爲19

這一直持續到退出事件並在隊列中留下19個項目。

如果您在退出事件觸發後添加了一個循環,並且由消費者處理,則可能會耗盡隊列的其餘部分。

這個例子只是試圖告訴你如何處理插入到隊列中的項目和消費者消費信號。想象一下,如果你有20位消費者,所有消費者都可以在不剔除隊列的情況下進行錄入。

關鍵取決於:lock(_queue.SyncRoot)和處理多個事件,一個用於NewItem插入,另一個用於退出循環。

+0

謝謝,如何修改示例,如果我想1)隊列是無限的; 2)消費者應該儘快將元素出隊? – javapowered 2011-04-30 14:37:51

0

爲什麼值得MSDN文章被刪除...終於!只要有一個消費者,代碼就可以正常工作。但是,如果你擴大到兩個或更多的消費者,那麼它很快就會崩潰,並且在某些情況下可能會讓消費者產生不利影響。除此之外,我還有很長一段時間都在關注這篇文章,所以很高興看到它終於消失了。

簡短的回答...不要依靠那個代碼來實際應用。