2011-07-19 68 views
1
private ConcurrentQueue<Data> _queue = new ConcurrentQueue<Data>(); 
private AutoResetEvent _queueNotifier = new AutoResetEvent(false); 

public void MoreData(Data example) 
{ 
    _queue.Enqueue(example); 
    _queueNotifier.Set(); 
} 

private void _SimpleThreadWorker() 
{ 
    while (_socket.Connected) 
    { 
     _queueNotifier.WaitOne(); 
     Data data; 
     if (_queue.TryDequeue(out data)) 
     { 
      //handle the data 
     } 
    } 
} 

當我擁有它時,我是否必須將該事件設置爲假當它返回_queueNotifier.WaitOne()或它是如何工作的時候,出列還是事件回到假?AutoResetEvent進程?

我是否應該像下面的例子那樣使用inner,或者兩種方式都好嗎?

while (_socket.Connected) 
{ 
    _queueNotifier.WaitOne(); 
    while (!_queue.IsEmpty) 
    { 
     Data data; 
     if (_queue.TryDequeue(out data)) 
     { 
      //handle the data 
     } 
    } 
} 

回答

4

如果您使用ConcurrentQueue從.NET 4中,最好避免做AutoResetEvent處理自己完全。相反,創建一個BlockingCollection來包裝ConcurrentQueue,並使用它 - 它可以滿足您的所有需求。 (如果你只是使用參數的構造函數創建一個BlockingCollection,它會反正爲你創建一個ConcurrentQueue

編輯:如果你真的想仍然使用AutoResetEvent,然後WaitOne將自動(並自動)重置事件 - 這是AutoResetEvent的「自動」部分。與ManualResetEvent比較,其中不是重置事件。

+0

我會檢查一下,但我仍然有興趣瞭解AutoResetEvent如何在未來再次需要時進一步瞭解它。 – Prix

+0

@Prix:已編輯以包含該信息。有關更多信息,請參閱AutoResetEvent的文檔。 –

+0

感謝您的更新,至於你剛纔說的話,我有點困惑,因爲將concurrentqueue包裝在blockingcollection中,而不是僅僅使用blockingcolletion更容易?如果你能,我會欣​​賞一些樣本,所以我可以更好地理解你在說什麼...... – Prix

1

當你做_queueNotifier.Set()事件變成信號。當被通知的事件和_queueNotifier.WaitOne()從其他線程調用,兩件事情(即在內核模式下)同時發生:

  • 事件變得unsignaled(因爲它是自動復位)
  • 線程調用WaitOne是暢通無阻

所以你不必自己明確設置事件狀態。

但是,正如Jon所說,如果您對共享變量所做的唯一操作是從隊列中推拉項目,只需使用BlockingCollection更方便。

如果你正在訪問多個共享變量,那麼圍繞它可能會有一個單獨的線程同步機制(你自己的)。

而且,在我看來,如果你要使用自己的代碼,將是更好的做這樣的事情:

public void MoreData(Data example) 
{ 
    var queueWasEmpty = _queue.IsEmpty; 
    _queue.Enqueue(example); 
    if (queueWasEmpty) { 
     _queueNotifier.Set(); 
    } 
} 

private void _SimpleThreadWorker() 
{ 
    while (_socket.Connected) 
    { 
     _queueNotifier.WaitOne(); 
     Data data; 
     while(!queue.IsEmpty) { 
      if (_queue.TryDequeue(out data)) 
      { 
       //handle the data 
      } 
     } 
    } 
} 

這樣你就不必去到內核模式(設置事件),只要消費者功能繁忙時項目被添加到隊列中。您還可以避免在消費者函數的每次迭代中進入內核模式。

對於後者來說,避免上下文切換的確是以增加_queue.IsEmpty測試爲代價的(其中一個糟糕的實現可能會做上下文切換);然而,這可能是作爲互鎖比較交換操作實現的,不需要進入內核模式。

聲明:我沒有檢查源代碼或IL,以驗證上述信息。

+0

謝謝,這是一個很好的解釋:) – Prix