#if MONO using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security.Permissions; using System.Threading; namespace System.Collections.Concurrent { internal struct VolatileBool { public volatile bool m_value; public VolatileBool(bool value) { this.m_value = value; } } /// Defines methods to manipulate thread-safe collections intended for producer/consumer usage. This interface provides a unified representation for producer/consumer collections so that higher level abstractions such as can use the collection as the underlying storage mechanism. /// Specifies the type of elements in the collection. [__DynamicallyInvokable] public interface IProducerConsumerCollection : IEnumerable, ICollection, IEnumerable { /// Copies the elements of the to an , starting at a specified index. /// The one-dimensional that is the destination of the elements copied from the . The array must have zero-based indexing. /// The zero-based index in at which copying begins. /// /// is a null reference (Nothing in Visual Basic). /// /// is less than zero. /// /// is equal to or greater than the length of the -or- The number of elements in the collection is greater than the available space from to the end of the destination . [__DynamicallyInvokable] void CopyTo(T[] array, int index); /// Attempts to add an object to the . /// true if the object was added successfully; otherwise, false. /// The object to add to the . /// The was invalid for this collection. [__DynamicallyInvokable] bool TryAdd(T item); /// Attempts to remove and return an object from the . /// true if an object was removed and returned successfully; otherwise, false. /// When this method returns, if the object was removed and returned successfully, contains the removed object. If no object was available to be removed, the value is unspecified. [__DynamicallyInvokable] bool TryTake(out T item); /// Copies the elements contained in the to a new array. /// A new array containing the elements copied from the . [__DynamicallyInvokable] T[] ToArray(); } /// Represents a thread-safe first in-first out (FIFO) collection. /// The type of the elements contained in the queue. [__DynamicallyInvokable, DebuggerDisplay("Count = {Count}"), ComVisible(false)] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] [Serializable] public class ConcurrentQueue : IProducerConsumerCollection, IEnumerable, ICollection, IEnumerable { private class Segment { internal volatile T[] m_array; internal volatile VolatileBool[] m_state; private volatile ConcurrentQueue.Segment m_next; internal readonly long m_index; private volatile int m_low; private volatile int m_high; private volatile ConcurrentQueue m_source; internal ConcurrentQueue.Segment Next { get { return this.m_next; } } internal bool IsEmpty { get { return this.Low > this.High; } } internal int Low { get { return Math.Min(this.m_low, 32); } } internal int High { get { return Math.Min(this.m_high, 31); } } internal Segment(long index, ConcurrentQueue source) { this.m_array = new T[32]; this.m_state = new VolatileBool[32]; this.m_high = -1; this.m_index = index; this.m_source = source; } internal void UnsafeAdd(T value) { this.m_high++; this.m_array[this.m_high] = value; this.m_state[this.m_high].m_value = true; } internal ConcurrentQueue.Segment UnsafeGrow() { ConcurrentQueue.Segment segment = new ConcurrentQueue.Segment(this.m_index + 1L, this.m_source); this.m_next = segment; return segment; } internal void Grow() { ConcurrentQueue.Segment next = new ConcurrentQueue.Segment(this.m_index + 1L, this.m_source); this.m_next = next; this.m_source.m_tail = this.m_next; } internal bool TryAppend(T value) { if (this.m_high >= 31) { return false; } int num = 32; try { } finally { num = Interlocked.Increment(ref this.m_high); if (num <= 31) { this.m_array[num] = value; this.m_state[num].m_value = true; } if (num == 31) { this.Grow(); } } return num <= 31; } internal bool TryRemove(out T result) { SpinWait spinWait = default(SpinWait); int i = this.Low; int high = this.High; while (i <= high) { if (Interlocked.CompareExchange(ref this.m_low, i + 1, i) == i) { SpinWait spinWait2 = default(SpinWait); while (!this.m_state[i].m_value) { spinWait2.SpinOnce(); } result = this.m_array[i]; if (this.m_source.m_numSnapshotTakers <= 0) { this.m_array[i] = default(T); } if (i + 1 >= 32) { spinWait2 = default(SpinWait); while (this.m_next == null) { spinWait2.SpinOnce(); } this.m_source.m_head = this.m_next; } return true; } spinWait.SpinOnce(); i = this.Low; high = this.High; } result = default(T); return false; } internal bool TryPeek(out T result) { result = default(T); int low = this.Low; if (low > this.High) { return false; } SpinWait spinWait = default(SpinWait); while (!this.m_state[low].m_value) { spinWait.SpinOnce(); } result = this.m_array[low]; return true; } internal void AddToList(List list, int start, int end) { for (int i = start; i <= end; i++) { SpinWait spinWait = default(SpinWait); while (!this.m_state[i].m_value) { spinWait.SpinOnce(); } list.Add(this.m_array[i]); } } } [NonSerialized] private volatile ConcurrentQueue.Segment m_head; [NonSerialized] private volatile ConcurrentQueue.Segment m_tail; private T[] m_serializationArray; [NonSerialized] internal volatile int m_numSnapshotTakers; private const int SEGMENT_SIZE = 32; /// Gets a value indicating whether access to the is synchronized with the SyncRoot. /// true if access to the is synchronized with the SyncRoot; otherwise, false. For , this property always returns false. [__DynamicallyInvokable] bool ICollection.IsSynchronized { [__DynamicallyInvokable] get { return false; } } /// Gets an object that can be used to synchronize access to the . This property is not supported. /// Returns null (Nothing in Visual Basic). /// The SyncRoot property is not supported. [__DynamicallyInvokable] object ICollection.SyncRoot { [__DynamicallyInvokable] get { throw new NotSupportedException("ConcurrentCollection_SyncRoot_NotSupported"); } } /// Gets a value that indicates whether the is empty. /// true if the is empty; otherwise, false. [__DynamicallyInvokable] public bool IsEmpty { [__DynamicallyInvokable] get { ConcurrentQueue.Segment head = this.m_head; if (!head.IsEmpty) { return false; } if (head.Next == null) { return true; } SpinWait spinWait = default(SpinWait); while (head.IsEmpty) { if (head.Next == null) { return true; } spinWait.SpinOnce(); head = this.m_head; } return false; } } /// Gets the number of elements contained in the . /// The number of elements contained in the . [__DynamicallyInvokable] public int Count { [__DynamicallyInvokable] get { ConcurrentQueue.Segment segment; ConcurrentQueue.Segment segment2; int num; int num2; this.GetHeadTailPositions(out segment, out segment2, out num, out num2); if (segment == segment2) { return num2 - num + 1; } int num3 = 32 - num; num3 += 32 * (int)(segment2.m_index - segment.m_index - 1L); return num3 + (num2 + 1); } } /// Initializes a new instance of the class. [__DynamicallyInvokable] public ConcurrentQueue() { this.m_head = (this.m_tail = new ConcurrentQueue.Segment(0L, this)); } private void InitializeFromCollection(IEnumerable collection) { ConcurrentQueue.Segment segment = new ConcurrentQueue.Segment(0L, this); this.m_head = segment; int num = 0; foreach (T current in collection) { segment.UnsafeAdd(current); num++; if (num >= 32) { segment = segment.UnsafeGrow(); num = 0; } } this.m_tail = segment; } /// Initializes a new instance of the class that contains elements copied from the specified collection /// The collection whose elements are copied to the new . /// The argument is null. [__DynamicallyInvokable] public ConcurrentQueue(IEnumerable collection) { if (collection == null) { throw new ArgumentNullException("collection"); } this.InitializeFromCollection(collection); } [OnSerializing] private void OnSerializing(StreamingContext context) { this.m_serializationArray = this.ToArray(); } [OnDeserialized] private void OnDeserialized(StreamingContext context) { this.InitializeFromCollection(this.m_serializationArray); this.m_serializationArray = null; } /// Copies the elements of the to an , starting at a particular index. /// The one-dimensional that is the destination of the elements copied from the . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// /// is a null reference (Nothing in Visual Basic). /// /// is less than zero. /// /// is multidimensional. -or- does not have zero-based indexing. -or- is equal to or greater than the length of the -or- The number of elements in the source is greater than the available space from to the end of the destination . -or- The type of the source cannot be cast automatically to the type of the destination . [__DynamicallyInvokable] void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ((ICollection)this.ToList()).CopyTo(array, index); } /// Returns an enumerator that iterates through a collection. /// An that can be used to iterate through the collection. [__DynamicallyInvokable] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } [__DynamicallyInvokable] bool IProducerConsumerCollection.TryAdd(T item) { this.Enqueue(item); return true; } [__DynamicallyInvokable] bool IProducerConsumerCollection.TryTake(out T item) { return this.TryDequeue(out item); } /// Copies the elements stored in the to a new array. /// A new array containing a snapshot of elements copied from the . [__DynamicallyInvokable] public T[] ToArray() { return this.ToList().ToArray(); } private List ToList() { Interlocked.Increment(ref this.m_numSnapshotTakers); List list = new List(); try { ConcurrentQueue.Segment segment; ConcurrentQueue.Segment segment2; int start; int end; this.GetHeadTailPositions(out segment, out segment2, out start, out end); if (segment == segment2) { segment.AddToList(list, start, end); } else { segment.AddToList(list, start, 31); for (ConcurrentQueue.Segment next = segment.Next; next != segment2; next = next.Next) { next.AddToList(list, 0, 31); } segment2.AddToList(list, 0, end); } } finally { Interlocked.Decrement(ref this.m_numSnapshotTakers); } return list; } private void GetHeadTailPositions(out ConcurrentQueue.Segment head, out ConcurrentQueue.Segment tail, out int headLow, out int tailHigh) { head = this.m_head; tail = this.m_tail; headLow = head.Low; tailHigh = tail.High; SpinWait spinWait = default(SpinWait); while (head != this.m_head || tail != this.m_tail || headLow != head.Low || tailHigh != tail.High || head.m_index > tail.m_index) { spinWait.SpinOnce(); head = this.m_head; tail = this.m_tail; headLow = head.Low; tailHigh = tail.High; } } /// Copies the elements to an existing one-dimensional , starting at the specified array index. /// The one-dimensional that is the destination of the elements copied from the . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// /// is a null reference (Nothing in Visual Basic). /// /// is less than zero. /// /// is equal to or greater than the length of the -or- The number of elements in the source is greater than the available space from to the end of the destination . [__DynamicallyInvokable] public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } this.ToList().CopyTo(array, index); } /// Returns an enumerator that iterates through the . /// An enumerator for the contents of the . [__DynamicallyInvokable] public IEnumerator GetEnumerator() { Interlocked.Increment(ref this.m_numSnapshotTakers); ConcurrentQueue.Segment head; ConcurrentQueue.Segment tail; int headLow; int tailHigh; this.GetHeadTailPositions(out head, out tail, out headLow, out tailHigh); return this.GetEnumerator(head, tail, headLow, tailHigh); } private IEnumerator GetEnumerator(ConcurrentQueue.Segment head, ConcurrentQueue.Segment tail, int headLow, int tailHigh) { try { SpinWait spinWait = default(SpinWait); if (head == tail) { for (int i = headLow; i <= tailHigh; i++) { spinWait.Reset(); while (!head.m_state[i].m_value) { spinWait.SpinOnce(); } yield return head.m_array[i]; } } else { for (int j = headLow; j < 32; j++) { spinWait.Reset(); while (!head.m_state[j].m_value) { spinWait.SpinOnce(); } yield return head.m_array[j]; } for (ConcurrentQueue.Segment next = head.Next; next != tail; next = next.Next) { for (int k = 0; k < 32; k++) { spinWait.Reset(); while (!next.m_state[k].m_value) { spinWait.SpinOnce(); } yield return next.m_array[k]; } } for (int l = 0; l <= tailHigh; l++) { spinWait.Reset(); while (!tail.m_state[l].m_value) { spinWait.SpinOnce(); } yield return tail.m_array[l]; } } } finally { Interlocked.Decrement(ref this.m_numSnapshotTakers); } yield break; } /// Adds an object to the end of the . /// The object to add to the end of the . The value can be a null reference (Nothing in Visual Basic) for reference types. [__DynamicallyInvokable] public void Enqueue(T item) { SpinWait spinWait = default(SpinWait); while (true) { ConcurrentQueue.Segment tail = this.m_tail; if (tail.TryAppend(item)) { break; } spinWait.SpinOnce(); } } /// Attempts to remove and return the object at the beginning of the . /// true if an element was removed and returned from the beginning of the successfully; otherwise, false. /// When this method returns, if the operation was successful, contains the object removed. If no object was available to be removed, the value is unspecified. [__DynamicallyInvokable] public bool TryDequeue(out T result) { while (!this.IsEmpty) { ConcurrentQueue.Segment head = this.m_head; if (head.TryRemove(out result)) { return true; } } result = default(T); return false; } /// Attempts to return an object from the beginning of the without removing it. /// true if and object was returned successfully; otherwise, false. /// When this method returns, contains an object from the beginning of the or an unspecified value if the operation failed. [__DynamicallyInvokable] public bool TryPeek(out T result) { while (!this.IsEmpty) { ConcurrentQueue.Segment head = this.m_head; if (head.TryPeek(out result)) { return true; } } result = default(T); return false; } } } #endif