Let me add another answer. Why is it above others?
1) Simplicity Trying to guarantee size is good, but it leads to unnecessary complexity, which can have its problems.
2) Implements IReadOnlyCollection, which means that you can use Linq on it and pass it into many things that expect IEnumerable.
3) No lock. Many of the solutions above use locks, which is wrong for a collection without locks.
4) Implements the same set of methods, properties and interfaces as ConcurrentQueue, including IProducerConsumerCollection, which is important if you want to use a collection with BlockingCollection.
This implementation can potentially lead to more entries than expected if TryDequeue fails, but the frequency of this occurrence does not seem to be worth the specialized code, which will inevitably slow down performance and cause its own unexpected problems.
If you absolutely want to guarantee size, implementing a Prune () or similar method seems like the best idea. You can use the ReaderWriterLockSlim read lock in other methods (including TryDequeue) and only block writing when deleted.
class ConcurrentFixedSizeQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>, ICollection { readonly ConcurrentQueue<T> m_concurrentQueue; readonly int m_maxSize; public int Count => m_concurrentQueue.Count; public bool IsEmpty => m_concurrentQueue.IsEmpty; public ConcurrentFixedSizeQueue (int maxSize) : this(Array.Empty<T>(), maxSize) { } public ConcurrentFixedSizeQueue (IEnumerable<T> initialCollection, int maxSize) { if (initialCollection == null) { throw new ArgumentNullException(nameof(initialCollection)); } m_concurrentQueue = new ConcurrentQueue<T>(initialCollection); m_maxSize = maxSize; } public void Enqueue (T item) { m_concurrentQueue.Enqueue(item); if (m_concurrentQueue.Count > m_maxSize) { T result; m_concurrentQueue.TryDequeue(out result); } } public void TryPeek (out T result) => m_concurrentQueue.TryPeek(out result); public bool TryDequeue (out T result) => m_concurrentQueue.TryDequeue(out result); public void CopyTo (T[] array, int index) => m_concurrentQueue.CopyTo(array, index); public T[] ToArray () => m_concurrentQueue.ToArray(); public IEnumerator<T> GetEnumerator () => m_concurrentQueue.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator () => GetEnumerator();
Josh Apr 13 '18 at 16:48 2018-04-13 16:48
source share