/// <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); } }
/// <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; } } } }