protected MpscLinkedQueueNode <T> GetAndSetTailRef(MpscLinkedQueueNode <T> value) { #pragma warning disable 420 return(Interlocked.Exchange(ref this.tailRef, value)); #pragma warning restore 420 }
public IEnumerator <T> GetEnumerator() { MpscLinkedQueueNode <T> node = this.PeekNode(); while (node != null) { yield return(node.Value); node = node.Next; } }
/// <summary> /// Returns the node right next to the head, which contains the first element of this queue. /// </summary> MpscLinkedQueueNode <T> PeekNode() { MpscLinkedQueueNode <T> head = this.HeadRef; MpscLinkedQueueNode <T> next = head.Next; if (next == null && head != this.TailRef) { // if tail != head this is not going to change until consumer makes progress // we can avoid reading the head and just spin on next until it shows up // // See https://github.com/akka/akka/pull/15596 do { next = head.Next; }while (next == null); } return(next); }
public T Dequeue() { MpscLinkedQueueNode <T> next = this.PeekNode(); if (next == null) { return(null); } // next becomes a new head. MpscLinkedQueueNode <T> oldHead = this.HeadRef; // todo: research storestore vs loadstore barriers // See: http://robsjava.blogspot.com/2013/06/a-faster-volatile.html // See: http://psy-lob-saw.blogspot.com/2012/12/atomiclazyset-is-performance-win-for.html this.HeadRef = next; // Break the linkage between the old head and the new head. oldHead.Unlink(); return(next.ClearMaybe()); }
public bool Enqueue(T value) { Contract.Requires(value != null); MpscLinkedQueueNode <T> newTail; var node = value as MpscLinkedQueueNode <T>; if (node != null) { newTail = node; newTail.Next = null; } else { newTail = new DefaultNode(value); } MpscLinkedQueueNode <T> oldTail = this.GetAndSetTailRef(newTail); oldTail.Next = newTail; return(true); }
public T Peek() { MpscLinkedQueueNode <T> next = this.PeekNode(); return(next == null ? null : next.Value); }