Implements a non-locking queue
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace Enyim.Collections { /// <summary> /// Implements a non-locking queue. /// </summary> /// <typeparam name="T"></typeparam> public class InterlockedQueue<T> { private Node head; private Node tail; /// <summary> /// Initializes a new instance of the <see cref="T:InterlockedQueue"/> class. /// </summary> public InterlockedQueue() { Node node = new Node(default(T)); this.head = node; this.tail = node; } /// <summary> /// Removes and returns the item at the beginning of the <see cref="T:InterlockedQueue"/>. /// </summary> /// <param name="value">The object that is removed from the beginning of the <see cref="T:InterlockedQueue"/>.</param> /// <returns><value>true</value> if an item was successfully dequeued; otherwise <value>false</value>.</returns> public bool Dequeue(out T value) { Node head; Node tail; Node next; while (true) { // read head head = this.head; tail = this.tail; next = head.Next; // Are head, tail, and next consistent? if (Object.ReferenceEquals(this.head, head)) { // is tail falling behind if (Object.ReferenceEquals(head.Next, tail.Next)) { // is the queue empty? if (Object.ReferenceEquals(next, null)) { value = default(T); // queue is empty and cannot dequeue return false; } Interlocked.CompareExchange<Node>( ref this.tail, next.Next, tail); } else // No need to deal with tail { // read value before CAS otherwise another deque might try to free the next node value = next.Value; // try to swing the head to the next node if (Interlocked.CompareExchange<Node>( ref this.head, next, head) == head) { return true; } } } } } /// <summary> /// Adds an object to the end of the <see cref="T:InterlockedQueue"/>. /// </summary> /// <param name="value">The item to be added to the <see cref="T:InterlockedQueue"/>. The value can be <value>null</value>.</param> public void Enqueue(T value) { // Allocate a new node from the free list Node valueNode = new Node(value); while (true) { Node tail = this.tail; Node next = tail.Next; // are tail and next consistent if (Object.ReferenceEquals(tail, this.tail)) { // was tail pointing to the last node? if (Object.ReferenceEquals(next, null)) { if (Object.ReferenceEquals( Interlocked.CompareExchange(ref tail.Next, valueNode, next), next ) ) { Interlocked.CompareExchange(ref this.tail, valueNode, tail); break; } } else // tail was not pointing to last node { // try to swing Tail to the next node Interlocked.CompareExchange<Node>(ref this.tail, next, tail); } } } } #region [ Node ] private class Node { public T Value; public Node Next; public Node(T value) { this.Value = value; } } #endregion } } #region [ License information ] /* ************************************************************ * * Copyright (c) Attila Kisk, enyim.com, 2007 * * This source code is subject to terms and conditions of * Microsoft Permissive License (Ms-PL). * * A copy of the license can be found in the License.html * file at the root of this distribution. If you can not * locate the License, please send an email to a@enyim.com * * By using this source code in any fashion, you are * agreeing to be bound by the terms of the Microsoft * Permissive License. * * You must not remove this notice, or any other, from this * software. * * ************************************************************/ #endregion