578 lines · 26.4 KB · C#
RawDownload
#if MONOusing 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;		}	} 	/// <summary>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 <see cref="T:System.Collections.Concurrent.BlockingCollection`1" /> can use the collection as the underlying storage mechanism.</summary>	/// <typeparam name="T">Specifies the type of elements in the collection.</typeparam>	[__DynamicallyInvokable]	public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection, IEnumerable	{		/// <summary>Copies the elements of the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" /> to an <see cref="T:System.Array" />, starting at a specified index.</summary>		/// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" />. The array must have zero-based indexing.</param>		/// <param name="index">The zero-based index in <paramref name="array" /> at which copying begins.</param>		/// <exception cref="T:System.ArgumentNullException">		///   <paramref name="array" /> is a null reference (Nothing in Visual Basic).</exception>		/// <exception cref="T:System.ArgumentOutOfRangeException">		///   <paramref name="index" /> is less than zero.</exception>		/// <exception cref="T:System.ArgumentException">		///   <paramref name="index" /> is equal to or greater than the length of the <paramref name="array" /> -or- The number of elements in the collection is greater than the available space from <paramref name="index" /> to the end of the destination <paramref name="array" />. </exception>		[__DynamicallyInvokable]		void CopyTo(T[] array, int index);		/// <summary>Attempts to add an object to the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" />.</summary>		/// <returns>true if the object was added successfully; otherwise, false.</returns>		/// <param name="item">The object to add to the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" />.</param>		/// <exception cref="T:System.ArgumentException">The <paramref name="item" /> was invalid for this collection.</exception>		[__DynamicallyInvokable]		bool TryAdd(T item);		/// <summary>Attempts to remove and return an object from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" />.</summary>		/// <returns>true if an object was removed and returned successfully; otherwise, false.</returns>		/// <param name="item">When this method returns, if the object was removed and returned successfully, <paramref name="item" /> contains the removed object. If no object was available to be removed, the value is unspecified.</param>		[__DynamicallyInvokable]		bool TryTake(out T item);		/// <summary>Copies the elements contained in the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" /> to a new array.</summary>		/// <returns>A new array containing the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1" />.</returns>		[__DynamicallyInvokable]		T[] ToArray();	}      /// <summary>Represents a thread-safe first in-first out (FIFO) collection.</summary>    /// <typeparam name="T">The type of the elements contained in the queue.</typeparam>    [__DynamicallyInvokable, DebuggerDisplay("Count = {Count}"), ComVisible(false)]    [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]    [Serializable]    public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable    {        private class Segment        {            internal volatile T[] m_array;            internal volatile VolatileBool[] m_state;            private volatile ConcurrentQueue<T>.Segment m_next;            internal readonly long m_index;            private volatile int m_low;            private volatile int m_high;            private volatile ConcurrentQueue<T> m_source;            internal ConcurrentQueue<T>.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<T> 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<T>.Segment UnsafeGrow()            {                ConcurrentQueue<T>.Segment segment = new ConcurrentQueue<T>.Segment(this.m_index + 1L, this.m_source);                this.m_next = segment;                return segment;            }            internal void Grow()            {                ConcurrentQueue<T>.Segment next = new ConcurrentQueue<T>.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<T> 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<T>.Segment m_head;        [NonSerialized]        private volatile ConcurrentQueue<T>.Segment m_tail;        private T[] m_serializationArray;        [NonSerialized]        internal volatile int m_numSnapshotTakers;        private const int SEGMENT_SIZE = 32;        /// <summary>Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection" /> is synchronized with the SyncRoot.</summary>        /// <returns>true if access to the <see cref="T:System.Collections.ICollection" /> is synchronized with the SyncRoot; otherwise, false. For <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />, this property always returns false.</returns>        [__DynamicallyInvokable]        bool ICollection.IsSynchronized        {            [__DynamicallyInvokable]            get            {                return false;            }        }        /// <summary>Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection" />. This property is not supported.</summary>        /// <returns>Returns null  (Nothing in Visual Basic).</returns>        /// <exception cref="T:System.NotSupportedException">The SyncRoot property is not supported.</exception>        [__DynamicallyInvokable]        object ICollection.SyncRoot        {            [__DynamicallyInvokable]            get            {                throw new NotSupportedException("ConcurrentCollection_SyncRoot_NotSupported");            }        }        /// <summary>Gets a value that indicates whether the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> is empty.</summary>        /// <returns>true if the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> is empty; otherwise, false.</returns>        [__DynamicallyInvokable]        public bool IsEmpty        {            [__DynamicallyInvokable]            get            {                ConcurrentQueue<T>.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;            }        }        /// <summary>Gets the number of elements contained in the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</summary>        /// <returns>The number of elements contained in the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</returns>        [__DynamicallyInvokable]        public int Count        {            [__DynamicallyInvokable]            get            {                ConcurrentQueue<T>.Segment segment;                ConcurrentQueue<T>.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);            }        }        /// <summary>Initializes a new instance of the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> class.</summary>        [__DynamicallyInvokable]        public ConcurrentQueue()        {            this.m_head = (this.m_tail = new ConcurrentQueue<T>.Segment(0L, this));        }        private void InitializeFromCollection(IEnumerable<T> collection)        {            ConcurrentQueue<T>.Segment segment = new ConcurrentQueue<T>.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;        }        /// <summary>Initializes a new instance of the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> class that contains elements copied from the specified collection</summary>        /// <param name="collection">The collection whose elements are copied to the new <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</param>        /// <exception cref="T:System.ArgumentNullException">The <paramref name="collection" /> argument is null.</exception>        [__DynamicallyInvokable]        public ConcurrentQueue(IEnumerable<T> 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;        }        /// <summary>Copies the elements of the <see cref="T:System.Collections.ICollection" /> to an <see cref="T:System.Array" />, starting at a particular <see cref="T:System.Array" /> index.</summary>        /// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.ConcurrentBag" />. The <see cref="T:System.Array" /> must have zero-based indexing.</param>        /// <param name="index">The zero-based index in <paramref name="array" /> at which copying begins.</param>        /// <exception cref="T:System.ArgumentNullException">        ///   <paramref name="array" /> is a null reference (Nothing in Visual Basic).</exception>        /// <exception cref="T:System.ArgumentOutOfRangeException">        ///   <paramref name="index" /> is less than zero.</exception>        /// <exception cref="T:System.ArgumentException">        ///   <paramref name="array" /> is multidimensional. -or- <paramref name="array" /> does not have zero-based indexing. -or- <paramref name="index" /> is equal to or greater than the length of the <paramref name="array" /> -or- The number of elements in the source <see cref="T:System.Collections.ICollection" /> is greater than the available space from <paramref name="index" /> to the end of the destination <paramref name="array" />. -or- The type of the source <see cref="T:System.Collections.ICollection" /> cannot be cast automatically to the type of the destination <paramref name="array" />.</exception>        [__DynamicallyInvokable]        void ICollection.CopyTo(Array array, int index)        {            if (array == null)            {                throw new ArgumentNullException("array");            }            ((ICollection)this.ToList()).CopyTo(array, index);        }        /// <summary>Returns an enumerator that iterates through a collection.</summary>        /// <returns>An <see cref="T:System.Collections.IEnumerator" /> that can be used to iterate through the collection.</returns>        [__DynamicallyInvokable]        IEnumerator IEnumerable.GetEnumerator()        {            return ((IEnumerable<T>)this).GetEnumerator();        }        [__DynamicallyInvokable]        bool IProducerConsumerCollection<T>.TryAdd(T item)        {            this.Enqueue(item);            return true;        }        [__DynamicallyInvokable]        bool IProducerConsumerCollection<T>.TryTake(out T item)        {            return this.TryDequeue(out item);        }        /// <summary>Copies the elements stored in the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> to a new array.</summary>        /// <returns>A new array containing a snapshot of elements copied from the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</returns>        [__DynamicallyInvokable]        public T[] ToArray()        {            return this.ToList().ToArray();        }        private List<T> ToList()        {            Interlocked.Increment(ref this.m_numSnapshotTakers);            List<T> list = new List<T>();            try            {                ConcurrentQueue<T>.Segment segment;                ConcurrentQueue<T>.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<T>.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<T>.Segment head, out ConcurrentQueue<T>.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;            }        }        /// <summary>Copies the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> elements to an existing one-dimensional <see cref="T:System.Array" />, starting at the specified array index.</summary>        /// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />. The <see cref="T:System.Array" /> must have zero-based indexing.</param>        /// <param name="index">The zero-based index in <paramref name="array" /> at which copying begins.</param>        /// <exception cref="T:System.ArgumentNullException">        ///   <paramref name="array" /> is a null reference (Nothing in Visual Basic).</exception>        /// <exception cref="T:System.ArgumentOutOfRangeException">        ///   <paramref name="index" /> is less than zero.</exception>        /// <exception cref="T:System.ArgumentException">        ///   <paramref name="index" /> is equal to or greater than the length of the <paramref name="array" /> -or- The number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" /> is greater than the available space from <paramref name="index" /> to the end of the destination <paramref name="array" />.</exception>        [__DynamicallyInvokable]        public void CopyTo(T[] array, int index)        {            if (array == null)            {                throw new ArgumentNullException("array");            }            this.ToList().CopyTo(array, index);        }        /// <summary>Returns an enumerator that iterates through the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</summary>        /// <returns>An enumerator for the contents of the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</returns>        [__DynamicallyInvokable]        public IEnumerator<T> GetEnumerator()        {            Interlocked.Increment(ref this.m_numSnapshotTakers);            ConcurrentQueue<T>.Segment head;            ConcurrentQueue<T>.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<T> GetEnumerator(ConcurrentQueue<T>.Segment head, ConcurrentQueue<T>.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<T>.Segment next = head.Next; next != tail; next = next.Next)                    {                        for (int k = 0; k < 32; k++)                        {                            spinWait.Reset();

Lines 1–500 of 578.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t