2013-06-25 48 views
0

我有一個可以從不同線程訪問的靜態隊列。這些枚舉/開始枚舉隊列嗎?

Queue有一個包裝器,它可以在add/remove/set上正確鎖定。 也有一種方法,我鎖定並返回Queue的副本,但這會產生一個新的枚舉,這有點浪費,所以我只想在必要時調用它。

我不想無謂地複製隊列,但枚舉它可以拋出一個異常,如果隊列被改變,而我在列舉上。

有沒有機會,這些拋出一個異常,而枚舉(因爲原因當然以上):

  • QueueWrapper.InnerQueue.Any()(清空任何)
  • QueueWrapper.InnerQueue.FirstOrDefault(o => o.Something)
  • QueueWrapper.InnerQueue.Except(element)

我應該在哪裏將QueueWrapper.InnerQueue替換爲QueueWrapper.GetQueueCopy()

+1

我不確定如何回答這個問題,但僅供參考,在.NET中有一個併發隊列可用:http://msdn.microsoft.com/fr-fr/library/vstudio/dd267265.aspx – C4stor

+0

* C4stor *是正確的:如果你可以使用**內置實現**可以大大簡化事情。 – Pragmateek

回答

0

當您更改基礎集合時,枚舉僅引發。 LINQ運營商(您的案例中的AnyFirstOrDefaultExcept)不會更改集合,因此它們不會拋出。

+0

否:)。但是如果一個調用'Any','First'或'Except'的線程和另一個線程在執行上述方法期間修改了集合,它們是否會拋出異常? – SoonDead

+0

是的,但這不是你可以準備的。如果你不同步('lock')這段代碼,並且你需要它是線程安全的,那麼,是的,不可變集合是要走的路。但是,如果它是一個選項,則同步代碼是您應該啓動的位置。在這種情況下,上述解釋仍然存在。 –

0

您顯示的所有操作確實會枚舉隊列,因此您無法在這些隊列中對其進行更改,因此它不是線程安全的(取決於您鎖定隊列更新操作的方式)。

如果你需要保護枚舉,那麼你需要一個更高層次的鎖定。

爲最佳,以避免鎖定新的讀者時,已經是你可以使用一個ReaderWriterLockSlimhttp://msdn.microsoft.com/library/system.threading.readerwriterlockslim.aspx)讀卡器。

您將有這樣的代碼:

ReaderWriterLockSlim rwls = new ReaderWriterLockSlim(); 
... 
rwls.EnterReadLock(); 
try 
{ 
    // some enumeration 
} 
finally 
{ 
    rwls.ExitReadLock(); 
} 
... 
rwls.EnterWriteLock(); 
try 
{ 
    // some bulk update 
} 
finally 
{ 
    rwls.ExitWriteLock(); 
} 

這種方式,您可以有N個並行枚舉只有一個更新在任何特定時間運行。