summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs')
-rw-r--r--src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs94
1 files changed, 50 insertions, 44 deletions
diff --git a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
index 82bc4f9f5c..d1c2d42dce 100644
--- a/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
+++ b/src/mscorlib/src/System/Collections/Concurrent/ConcurrentStack.cs
@@ -1,25 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#pragma warning disable 0420
-
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
-//
+// ConcurrentStack.cs
//
// A lock-free, concurrent stack primitive, and its associated debugger view type.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-using System;
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.Serialization;
-using System.Security;
using System.Threading;
namespace System.Collections.Concurrent
@@ -51,8 +43,8 @@ namespace System.Collections.Concurrent
/// </summary>
private class Node
{
- internal readonly T m_value; // Value of the node.
- internal Node m_next; // Next pointer.
+ internal readonly T _value; // Value of the node.
+ internal Node _next; // Next pointer.
/// <summary>
/// Constructs a new node with the specified value and no next node.
@@ -60,13 +52,12 @@ namespace System.Collections.Concurrent
/// <param name="value">The value of the node.</param>
internal Node(T value)
{
- m_value = value;
- m_next = null;
+ _value = value;
+ _next = null;
}
}
- private volatile Node m_head; // The stack is a singly linked list, and only remembers the head.
-
+ private volatile Node _head; // The stack is a singly linked list, and only remembers the head.
private const int BACKOFF_MAX_YIELDS = 8; // Arbitrary number to cap backoff.
/// <summary>
@@ -101,7 +92,7 @@ namespace System.Collections.Concurrent
// they are being dequeued. If we ever changed this (e.g. to pool nodes somehow),
// we'd need to revisit this implementation.
- for (Node curr = m_head; curr != null; curr = curr.m_next)
+ for (Node curr = _head; curr != null; curr = curr._next)
{
count++; //we don't handle overflow, to be consistent with existing generic collection types in CLR
}
@@ -110,6 +101,7 @@ namespace System.Collections.Concurrent
}
}
+
/// <summary>
/// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"/> is
/// synchronized with the SyncRoot.
@@ -135,7 +127,8 @@ namespace System.Collections.Concurrent
{
get
{
- throw new NotSupportedException(SR.ConcurrentCollection_SyncRoot_NotSupported);
+ ThrowHelper.ThrowNotSupportedException(ExceptionResource.ConcurrentCollection_SyncRoot_NotSupported);
+ return default(object);
}
}
@@ -169,7 +162,7 @@ namespace System.Collections.Concurrent
// Validate arguments.
if (array == null)
{
- throw new ArgumentNullException(nameof(array));
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
// We must be careful not to corrupt the array, so we will first accumulate an
@@ -203,7 +196,7 @@ namespace System.Collections.Concurrent
{
if (array == null)
{
- throw new ArgumentNullException(nameof(array));
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
// We must be careful not to corrupt the array, so we will first accumulate an
@@ -213,7 +206,7 @@ namespace System.Collections.Concurrent
ToList().CopyTo(array, index);
}
-
+#pragma warning disable 0420 // No warning for Interlocked.xxx if compiled with new managed compiler (Roslyn)
/// <summary>
/// Inserts an object at the top of the <see cref="ConcurrentStack{T}"/>.
/// </summary>
@@ -228,8 +221,8 @@ namespace System.Collections.Concurrent
// contention at the head, and then go back around and retry.
Node newNode = new Node(item);
- newNode.m_next = m_head;
- if (Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next)
+ newNode._next = _head;
+ if (Interlocked.CompareExchange(ref _head, newNode, newNode._next) == newNode._next)
{
return;
}
@@ -249,15 +242,15 @@ namespace System.Collections.Concurrent
{
SpinWait spin = new SpinWait();
- // Keep trying to CAS the exising head with the new node until we succeed.
+ // Keep trying to CAS the existing head with the new node until we succeed.
do
{
spin.SpinOnce();
// Reread the head and link our new node.
- tail.m_next = m_head;
+ tail._next = _head;
}
while (Interlocked.CompareExchange(
- ref m_head, head, tail.m_next) != tail.m_next);
+ ref _head, head, tail._next) != tail._next);
}
/// <summary>
@@ -269,19 +262,19 @@ namespace System.Collections.Concurrent
/// </param>
/// <returns>true if an element was removed and returned from the top of the <see
/// cref="ConcurrentStack{T}"/>
- /// succesfully; otherwise, false.</returns>
+ /// successfully; otherwise, false.</returns>
public bool TryPop(out T result)
{
- Node head = m_head;
+ Node head = _head;
//stack is empty
if (head == null)
{
result = default(T);
return false;
}
- if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head)
+ if (Interlocked.CompareExchange(ref _head, head._next, head) == head)
{
- result = head.m_value;
+ result = head._value;
return true;
}
@@ -300,7 +293,7 @@ namespace System.Collections.Concurrent
if (TryPopCore(1, out poppedNode) == 1)
{
- result = poppedNode.m_value;
+ result = poppedNode._value;
return true;
}
@@ -317,7 +310,8 @@ namespace System.Collections.Concurrent
/// When this method returns, if the pop succeeded, contains the removed object. If no object was
/// available to be removed, the value is unspecified. This parameter is passed uninitialized.
/// </param>
- /// <returns>True if an element was removed and returned; otherwise, false.</returns>
+ /// <returns>The number of objects successfully popped from the top of
+ /// the <see cref="ConcurrentStack{T}"/>.</returns>
private int TryPopCore(int count, out Node poppedHead)
{
SpinWait spin = new SpinWait();
@@ -330,7 +324,7 @@ namespace System.Collections.Concurrent
Random r = null;
while (true)
{
- head = m_head;
+ head = _head;
// Is the stack empty?
if (head == null)
{
@@ -339,13 +333,13 @@ namespace System.Collections.Concurrent
}
next = head;
int nodesCount = 1;
- for (; nodesCount < count && next.m_next != null; nodesCount++)
+ for (; nodesCount < count && next._next != null; nodesCount++)
{
- next = next.m_next;
+ next = next._next;
}
// Try to swap the new head. If we succeed, break out of the loop.
- if (Interlocked.CompareExchange(ref m_head, next.m_next, head) == head)
+ if (Interlocked.CompareExchange(ref _head, next._next, head) == head)
{
// Return the popped Node.
poppedHead = head;
@@ -372,6 +366,7 @@ namespace System.Collections.Concurrent
}
}
}
+#pragma warning restore 0420
/// <summary>
/// Copies the items stored in the <see cref="ConcurrentStack{T}"/> to a new array.
@@ -380,23 +375,34 @@ namespace System.Collections.Concurrent
/// cref="ConcurrentStack{T}"/>.</returns>
public T[] ToArray()
{
- return ToList().ToArray();
+ Node curr = _head;
+ return curr == null ?
+ Array.Empty<T>() :
+ ToList(curr).ToArray();
}
/// <summary>
/// Returns an array containing a snapshot of the list's contents, using
/// the target list node as the head of a region in the list.
/// </summary>
- /// <returns>An array of the list's contents.</returns>
+ /// <returns>A list of the stack's contents.</returns>
private List<T> ToList()
{
+ return ToList(_head);
+ }
+
+ /// <summary>
+ /// Returns an array containing a snapshot of the list's contents starting at the specified node.
+ /// </summary>
+ /// <returns>A list of the stack's contents starting at the specified node.</returns>
+ private List<T> ToList(Node curr)
+ {
List<T> list = new List<T>();
- Node curr = m_head;
while (curr != null)
{
- list.Add(curr.m_value);
- curr = curr.m_next;
+ list.Add(curr._value);
+ curr = curr._next;
}
return list;
@@ -421,8 +427,8 @@ namespace System.Collections.Concurrent
//If we put yield-return here, the iterator will be lazily evaluated. As a result a snapshot of
//the stack is not taken when GetEnumerator is initialized but when MoveNext() is first called.
//This is inconsistent with existing generic collections. In order to prevent it, we capture the
- //value of m_head in a buffer and call out to a helper method
- return GetEnumerator(m_head);
+ //value of _head in a buffer and call out to a helper method
+ return GetEnumerator(_head);
}
private IEnumerator<T> GetEnumerator(Node head)
@@ -430,8 +436,8 @@ namespace System.Collections.Concurrent
Node current = head;
while (current != null)
{
- yield return current.m_value;
- current = current.m_next;
+ yield return current._value;
+ current = current._next;
}
}