Exemplo n.º 1
0
 /// <summary>
 /// Removes all objects from the <see cref="ConcurrentQueue{T}"/>.
 /// </summary>
 public void Clear()
 {
     lock (_crossSegmentLock)
     {
         // Simply substitute a new segment for the existing head/tail,
         // as is done in the constructor.  Operations currently in flight
         // may still read from or write to an existing segment that's
         // getting dropped, meaning that in flight operations may not be
         // linear with regards to this clear operation.  To help mitigate
         // in-flight operations enqueuing onto the tail that's about to
         // be dropped, we first freeze it; that'll force enqueuers to take
         // this lock to synchronize and see the new tail.
         _tail.EnsureFrozenForEnqueues();
         _tail = _head = new ConcurrentQueueSegment <T>(InitialSegmentLength);
     }
 }
Exemplo n.º 2
0
        /// <summary>Adds to the end of the queue, adding a new segment if necessary.</summary>
        private void EnqueueSlow(T item)
        {
            while (true)
            {
                ConcurrentQueueSegment <T> tail = _tail;

                // Try to append to the existing tail.
                if (tail.TryEnqueue(item))
                {
                    return;
                }

                // If we were unsuccessful, take the lock so that we can compare and manipulate
                // the tail.  Assuming another enqueuer hasn't already added a new segment,
                // do so, then loop around to try enqueueing again.
                lock (_crossSegmentLock)
                {
                    if (tail == _tail)
                    {
                        // Make sure no one else can enqueue to this segment.
                        tail.EnsureFrozenForEnqueues();

                        // We determine the new segment's length based on the old length.
                        // In general, we double the size of the segment, to make it less likely
                        // that we'll need to grow again.  However, if the tail segment is marked
                        // as preserved for observation, something caused us to avoid reusing this
                        // segment, and if that happens a lot and we grow, we'll end up allocating
                        // lots of wasted space.  As such, in such situations we reset back to the
                        // initial segment length; if these observations are happening frequently,
                        // this will help to avoid wasted memory, and if they're not, we'll
                        // relatively quickly grow again to a larger size.
                        int nextSize = tail._preservedForObservation ? InitialSegmentLength : Math.Min(tail.Capacity * 2, MaxSegmentLength);
                        var newTail  = new ConcurrentQueueSegment <T>(nextSize);

                        // Hook up the new tail.
                        tail._nextSegment = newTail;
                        _tail             = newTail;
                    }
                }
            }
        }