예제 #1
0
        //private int m_count = 0;

        #endregion

        #region Constructor

        public LockFreeQueue(NodeManager <T> nodeManager)
        {
            m_nodeManager = (nodeManager == null) ? NodeManager <T> .Default : nodeManager;
            // Get a single node and make the head and tail refer to it
            // The node's Next field is null marking the end of the queue
            m_head = m_nodeManager.Allocate();
            m_tail = m_head;
        }
예제 #2
0
        public override void Free(LockFreeNode <T> node)
        {
            node.Item = default(T);             // Allow early GC

            // Try to make the new node be the head of the stack
            do
            {
                // Make the new node refer to the old head
                node.Next = m_head.Next;

                // If previous head's next == what we thought was next, change head's Next to the new node
                // else, try again if another thread changed the head
            } while (!InterlockedEx.IfThen(ref m_head.Next, node.Next, node));
        }
예제 #3
0
        public Boolean TryDequeue(out T item)
        {
            item = default(T);

            // Loop until we manage to advance the head, removing
            // a node (if there are no nodes to dequeue, we'll exit the method instead)
            for (Boolean dequeuedNode = false; !dequeuedNode;)
            {
                // make local copies of the head, the tail, and the head's Next reference
                LockFreeNode <T> tempHead     = m_head;
                LockFreeNode <T> tempTail     = m_tail;
                LockFreeNode <T> tempHeadNext = tempHead.Next;

                // If another thread changed the head, start over
                Thread.MemoryBarrier();                 // Make sure the value read from m_head is fresh

                if (tempHead != m_head)
                {
                    continue;
                }

                // If the head equals the tail
                if (tempHead == tempTail)
                {
                    // If the head node refers to null, then the queue is empty
                    if (tempHeadNext == null)
                    {
                        return(false);
                    }

                    // The head refers to the tail whose Next is not null. This means
                    // we have a lagging tail; update it
                    InterlockedEx.IfThen(ref m_tail, tempTail, tempHeadNext);
                    continue;
                }

                // The head and tail nodes are different; dequeue the head node and advance the head
                item         = tempHeadNext.Item;
                dequeuedNode = InterlockedEx.IfThen(ref m_head, tempHead, tempHeadNext);

                if (dequeuedNode)
                {
                    m_nodeManager.Free(tempHead);
                }
            }
            //Interlocked.Decrement(ref m_count);
            return(true);
        }
예제 #4
0
        // If two threads call Enqueue simultaneously:
        // Both threads create and initialize a new node
        // The tail's Next will refer to one of these 2 new nodes
        // The new new tail's Next will refer to the other of the 2 new nodes
        // m_tail will refer to the 1st new node appended (not the real tail)
        // To fix this: Enqueue initializes by advancing m_tail to the node whose Next is null
        public void Enqueue(T item)
        {
            // Get (or allocate) a node and initialize it
            LockFreeNode <T> newNode = m_nodeManager.Allocate(item);

            LockFreeNode <T> tempTail = null;

            for (Boolean appendedNewNode = false; !appendedNewNode;)
            {
                // Get the current tail and what IT refers to
                tempTail = m_tail;
                LockFreeNode <T> tempTailNext = tempTail.Next;

                // If another thread changed the tail, start over
                Thread.MemoryBarrier();                 // Make sure the value read from m_tail is fresh

                if (tempTail != m_tail)
                {
                    continue;
                }

                // If the tail isn't truely the tail, fix the tail, start over
                if (tempTailNext != null)
                {
                    // This can happen if multiple threads append nodes at the same time
                    // A new node thinks it's the tail (Next is null) as another thread's new node
                    // updates the previous node's Nextthinks it's the tail's Next field may not
                    InterlockedEx.IfThen(ref m_tail, tempTail, tempTailNext);
                    continue;
                }

                // The tail is truely the tail, try to append the new node
                appendedNewNode = InterlockedEx.IfThen(ref tempTail.Next, null, newNode);
            }

            // When new node is sucessfully appended, make the tail refer to it
            // This can fail if another thread scoots in. If this happens, our node is
            // appended to the linked-list but m_tail refers to another node that is not
            // the tail. The next Enqueue/Dequeue call will fix m_tail
            InterlockedEx.IfThen(ref m_tail, tempTail, newNode);

            //Interlocked.Increment(ref m_count);
        }
예제 #5
0
 public virtual void Free(LockFreeNode <T> node)
 {
     node.Item = default(T);             // Allow early GC
 }