// Needed for NET40 #if !NET_4_6 using System; using System.Collections.Generic; using System.Threading; namespace LinqInternal.Collections.ThreadSafe { /// /// Represent a fixed size thread-safe wait-free queue. /// /// The type of items stored in the queue. [Serializable] internal sealed class SafeQueue : IEnumerable { private int _count; private Node _root; private Node _tail; /// /// Initializes a new instance of the class. /// public SafeQueue() { _root = new Node(); _tail = _root; } /// /// Initializes a new instance of the class. /// public SafeQueue(IEnumerable source) { _root = new Node(source); _count = _root.Queue.Count; _tail = _root; } /// /// Gets the number of items actually contained. /// public int Count { get { return Volatile.Read(ref _count); } } /// /// Attempts to Adds the specified item at the front. /// /// The item. public void Add(T item) { loop: if (_tail.Queue.Add(item)) { Interlocked.Increment(ref _count); } else { var created = new Node(); var found = Interlocked.CompareExchange(ref _tail.Next, created, null); _tail = found ?? created; goto loop; } } /// /// Returns an that allows to iterate through the collection. /// /// /// A that can be used to iterate through the collection. /// public IEnumerator GetEnumerator() { var root = _root; do { foreach (var item in root.Queue) { yield return item; } root = root.Next; } while (root != null); } /// /// Attempts to retrieve the next item to be taken from the back without removing it. /// /// The item retrieved. /// /// true if an item was retrieved; otherwise, false. /// public bool TryPeek(out T item) { var root = _root; while (true) { if (_root.Queue.TryPeek(out item)) { return true; } if (root.Next != null) { var found = Interlocked.CompareExchange(ref _root, root.Next, root); root = found == root ? root.Next : found; } else { break; } } item = default(T); return false; } /// /// Attempts to retrieve and remove the next item from the back. /// /// The item. /// /// true if the item was taken; otherwise, false. /// public bool TryTake(out T item) { var root = _root; while (true) { if (_root.Queue.TryTake(out item)) { Interlocked.Decrement(ref _count); return true; } if (root.Next != null) { var found = Interlocked.CompareExchange(ref _root, root.Next, root); root = found == root ? root.Next : found; } else { break; } } item = default(T); return false; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } [Serializable] private class Node { internal readonly FixedSizeQueue Queue; internal Node Next; public Node() { Queue = new FixedSizeQueue(64); } public Node(IEnumerable source) { Queue = new FixedSizeQueue(source); } } } } #endif