/// <summary> /// Initializes the contents of the stack from an existing collection. /// </summary> /// <param name="collection">A collection from which to copy elements.</param> private void InitializeFromCollection(IEnumerable <T> collection) { // We just copy the contents of the collection to our stack. Node lastNode = null; foreach (T element in collection) { Node newNode = (this.usePool == true ? PoolClassMainThread <Node> .Spawn() : new Node()); newNode.m_value = element; newNode.m_next = lastNode; lastNode = newNode; } m_head = lastNode; }
/// <summary> /// Local helper function to Pop an item from the stack, slow path /// </summary> /// <param name="result">The popped item</param> /// <returns>True if succeeded, false otherwise</returns> private bool TryPopCore(out T result) { Node poppedNode; if (TryPopCore(1, out poppedNode) == 1) { result = poppedNode.m_value; if (this.usePool == true) { PoolClassMainThread <Node> .Recycle(ref poppedNode); } return(true); } result = default(T); return(false); }
/// <summary> /// Inserts an object at the top of the <see cref="ConcurrentStack{T}"/>. /// </summary> /// <param name="item">The object to push onto the <see cref="ConcurrentStack{T}"/>. The value can be /// a null reference (Nothing in Visual Basic) for reference types. /// </param> public void Push(T item) { // Pushes a node onto the front of the stack thread-safely. Internally, this simply // swaps the current head pointer using a (thread safe) CAS operation to accomplish // lock freedom. If the CAS fails, we add some back off to statistically decrease // contention at the head, and then go back around and retry. Node newNode = (this.usePool == true ? PoolClassMainThread <Node> .Spawn() : new Node()); newNode.m_value = item; newNode.m_next = m_head; if (Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next) { return; } // If we failed, go to the slow path and loop around until we succeed. PushCore(newNode, newNode); }
/// <summary> /// Removes all objects from the <see cref="ConcurrentStack{T}"/>. /// </summary> public void Clear() { // Clear the list by setting the head to null. We don't need to use an atomic // operation for this: anybody who is mutating the head by pushing or popping // will need to use an atomic operation to guarantee they serialize and don't // overwrite our setting of the head to null. var current = this.m_head; this.m_head = null; if (this.usePool == true) { while (current != null) { PoolClassMainThread <Node> .Recycle(ref current); current = current.m_next; } } }
/// <summary> /// Attempts to pop and return the object at the top of the <see cref="ConcurrentStack{T}"/>. /// </summary> /// <param name="result"> /// When this method returns, if the operation was successful, <paramref name="result"/> contains the /// object removed. If no object was available to be removed, the value is unspecified. /// </param> /// <returns>true if an element was removed and returned from the top of the <see /// cref="ConcurrentStack{T}"/> /// succesfully; otherwise, false.</returns> public bool TryPop(out T result) { Node head = m_head; //stack is empty if (head == null) { result = default(T); return(false); } if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head) { result = head.m_value; if (this.usePool == true) { PoolClassMainThread <Node> .Recycle(ref head); } return(true); } // Fall through to the slow path. return(TryPopCore(out result)); }