/// <summary> /// Dequeue /// </summary> /// <returns></returns> protected internal virtual LinkedNode Deq() { LinkedNode p = head; if (p != null && (head = p.Next) == null) { last = null; } return(p); }
/// <summary> /// Enqueue /// </summary> /// <param name="p">node to enqueue</param> protected internal virtual void Enq(LinkedNode p) { if (last == null) { last = head = p; } else { last = last.Next = p; } }
/// <summary> Create a queue with the given capacity</summary> /// <exception cref="ArgumentException"> if capacity less or equal to zero /// /// </exception> public BoundedLinkedQueue(int capacity) { if (capacity <= 0) { throw new ArgumentException(); } capacity_ = capacity; putSidePutPermits_ = capacity; head_ = new LinkedNode(null); last_ = head_; }
/// <summary> Create and insert a node. /// Call only under synch on putGuard_ /// /// </summary> protected internal virtual void Insert(Object x) { --putSidePutPermits_; LinkedNode p = new LinkedNode(x); lock (last_) { last_.Next = p; last_ = p; } }
/// <summary> /// <see cref="IChannel.Peek"/> /// </summary> public virtual Object Peek() { lock (head_) { LinkedNode first = head_.Next; if (first != null) { return(first.Value); } else { return(null); } } }
/// <summary>Main mechanics for put/offer *</summary> protected internal virtual void insert(Object x) { lock (putLock_) { LinkedNode p = new LinkedNode(x); lock (last_) { last_.Next = p; last_ = p; } if (waitingForTake_ > 0) { Monitor.Pulse(putLock_); } } }
/// <summary>Main mechanics for take/poll *</summary> protected internal virtual Object Extract() { lock (this) { lock (head_) { Object x = null; LinkedNode first = head_.Next; if (first != null) { x = first.Value; first.Value = null; head_ = first; } return(x); } } }
/// <summary>Main mechanics for take/poll *</summary> protected internal virtual Object Extract() { lock (this) { lock (head_) { Object x = null; LinkedNode first = head_.Next; if (first != null) { x = first.Value; first.Value = null; head_ = first; ++takeSidePutPermits_; Monitor.Pulse(this); } return(x); } } }
/// <summary>Main mechanics for put/offer *</summary> protected internal virtual void insert(Object x) { lock (putLock_) { LinkedNode p = new LinkedNode(x); lock (last_) { last_.Next = p; last_ = p; } if (waitingForTake_ > 0) Monitor.Pulse(putLock_); } }
/// <summary> /// creates a new queue with a node not paired to any object /// </summary> public LinkedQueue() { head_ = new LinkedNode(null); last_ = head_; }
/// <summary> /// Creates a node /// </summary> /// <param name="x">the object paired to this node</param> /// <param name="n">a node to link to</param> public LinkedNode(Object x, LinkedNode n) { Value = x; Next = n; }
/// <summary>Main mechanics for take/poll *</summary> protected internal virtual Object Extract() { lock (this) { lock (head_) { Object x = null; LinkedNode first = head_.Next; if (first != null) { x = first.Value; first.Value = null; head_ = first; } return x; } } }
/* * Offer and poll are just like put and take, except even messier. */ /// <summary> /// <see cref="IPuttable.Offer"/> /// </summary> public virtual bool Offer(Object x, long msecs) { if (x == null) { throw new ArgumentException(); } long waitTime = msecs; long startTime = 0; // lazily initialize below if needed for (; ;) { Utils.FailFastIfInterrupted(); LinkedNode slot; LinkedNode item = null; lock (this) { slot = waitingTakes.Deq(); if (slot == null) { if (waitTime <= 0) { return(false); } else { waitingPuts.Enq(item = new LinkedNode(x)); } } } if (slot != null) { lock (slot) { if (slot.Value != Cancelled) { slot.Value = x; Monitor.Pulse(slot); return(true); } } } long now = Utils.CurrentTimeMillis; if (startTime == 0) { startTime = now; } else { waitTime = msecs - (now - startTime); } if (item != null) { lock (item) { try { for (; ;) { if (item.Value == null) { return(true); } if (waitTime <= 0) { item.Value = Cancelled; return(false); } Monitor.Wait(item, TimeSpan.FromMilliseconds(waitTime)); waitTime = msecs - (Utils.CurrentTimeMillis - startTime); } } catch (ThreadInterruptedException ie) { if (item.Value == null) { Thread.CurrentThread.Interrupt(); return(true); } else { item.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// <see cref="ITakable.Poll"/> /// </summary> public virtual Object Poll(long msecs) { long waitTime = msecs; long startTime = 0; for (; ;) { Utils.FailFastIfInterrupted(); LinkedNode item; LinkedNode slot = null; lock (this) { item = waitingPuts.Deq(); if (item == null) { if (waitTime <= 0) { return(null); } else { waitingTakes.Enq(slot = new LinkedNode()); } } } if (item != null) { lock (item) { Object x = item.Value; if (x != Cancelled) { item.Value = null; item.Next = null; Monitor.Pulse(item); return(x); } } } long now = Utils.CurrentTimeMillis; if (startTime == 0) { startTime = now; } else { waitTime = msecs - (now - startTime); } if (slot != null) { lock (slot) { try { for (; ;) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; return(x); } if (waitTime <= 0) { slot.Value = Cancelled; return(null); } Monitor.Wait(slot, TimeSpan.FromMilliseconds(waitTime)); waitTime = msecs - (Utils.CurrentTimeMillis - startTime); } } catch (ThreadInterruptedException ie) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; Thread.CurrentThread.Interrupt(); return(x); } else { slot.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// <see cref="IPuttable.Put"/> /// </summary> public virtual void Put(Object x) { if (x == null) { throw new ArgumentException(); } // This code is conceptually straightforward, but messy // because we need to intertwine handling of put-arrives first // vs take-arrives first cases. // Outer loop is to handle retry due to cancelled waiting taker for (; ;) { // Get out now if we are interrupted Utils.FailFastIfInterrupted(); // Exactly one of item or slot will be nonnull at end of // synchronized block, depending on whether a put or a take // arrived first. LinkedNode slot; LinkedNode item = null; lock (this) { // Try to match up with a waiting taker; fill and signal it below slot = waitingTakes.Deq(); // If no takers yet, create a node and wait below if (slot == null) { waitingPuts.Enq(item = new LinkedNode(x)); } } if (slot != null) { // There is a waiting taker. // Fill in the slot created by the taker and signal taker to // continue. lock (slot) { if (slot.Value != Cancelled) { slot.Value = x; Monitor.Pulse(slot); return; } // else the taker has cancelled, so retry outer loop } } else { // Wait for a taker to arrive and take the item. lock (item) { try { while (item.Value != null) { Monitor.Wait(item); } return; } catch (ThreadInterruptedException ie) { // If item was taken, return normally but set interrupt status if (item.Value == null) { Thread.CurrentThread.Interrupt(); return; } else { item.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// <see cref="ITakable.Poll"/> /// </summary> public virtual Object Poll(long msecs) { long waitTime = msecs; long startTime = 0; for (; ; ) { Utils.FailFastIfInterrupted(); LinkedNode item; LinkedNode slot = null; lock (this) { item = waitingPuts.Deq(); if (item == null) { if (waitTime <= 0) return null; else waitingTakes.Enq(slot = new LinkedNode()); } } if (item != null) { lock (item) { Object x = item.Value; if (x != Cancelled) { item.Value = null; item.Next = null; Monitor.Pulse(item); return x; } } } long now = Utils.CurrentTimeMillis; if (startTime == 0) startTime = now; else waitTime = msecs - (now - startTime); if (slot != null) { lock (slot) { try { for (; ; ) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; return x; } if (waitTime <= 0) { slot.Value = Cancelled; return null; } Monitor.Wait(slot, TimeSpan.FromMilliseconds(waitTime)); waitTime = msecs - (Utils.CurrentTimeMillis - startTime); } } catch (ThreadInterruptedException ie) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; Thread.CurrentThread.Interrupt(); return x; } else { slot.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary>Main mechanics for take/poll *</summary> protected internal virtual Object Extract() { lock (this) { lock (head_) { Object x = null; LinkedNode first = head_.Next; if (first != null) { x = first.Value; first.Value = null; head_ = first; ++takeSidePutPermits_; Monitor.Pulse(this); } return x; } } }
/// <summary> /// <see cref="ITakable.Take"/> /// </summary> public virtual Object Take() { // Entirely symmetric to put() for (; ; ) { Utils.FailFastIfInterrupted(); LinkedNode item; LinkedNode slot = null; lock (this) { item = waitingPuts.Deq(); if (item == null) waitingTakes.Enq(slot = new LinkedNode()); } if (item != null) { lock (item) { Object x = item.Value; if (x != Cancelled) { item.Value = null; item.Next = null; Monitor.Pulse(item); return x; } } } else { lock (slot) { try { for (; ; ) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; return x; } else Monitor.Wait(slot); } } catch (ThreadInterruptedException ie) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; Thread.CurrentThread.Interrupt(); return x; } else { slot.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// <see cref="IPuttable.Put"/> /// </summary> public virtual void Put(Object x) { if (x == null) throw new ArgumentException(); // This code is conceptually straightforward, but messy // because we need to intertwine handling of put-arrives first // vs take-arrives first cases. // Outer loop is to handle retry due to cancelled waiting taker for (; ; ) { // Get out now if we are interrupted Utils.FailFastIfInterrupted(); // Exactly one of item or slot will be nonnull at end of // synchronized block, depending on whether a put or a take // arrived first. LinkedNode slot; LinkedNode item = null; lock (this) { // Try to match up with a waiting taker; fill and signal it below slot = waitingTakes.Deq(); // If no takers yet, create a node and wait below if (slot == null) waitingPuts.Enq(item = new LinkedNode(x)); } if (slot != null) { // There is a waiting taker. // Fill in the slot created by the taker and signal taker to // continue. lock (slot) { if (slot.Value != Cancelled) { slot.Value = x; Monitor.Pulse(slot); return ; } // else the taker has cancelled, so retry outer loop } } else { // Wait for a taker to arrive and take the item. lock (item) { try { while (item.Value != null) Monitor.Wait(item); return ; } catch (ThreadInterruptedException ie) { // If item was taken, return normally but set interrupt status if (item.Value == null) { Thread.CurrentThread.Interrupt(); return ; } else { item.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// <see cref="ITakable.Take"/> /// </summary> public virtual Object Take() { // Entirely symmetric to put() for (; ;) { Utils.FailFastIfInterrupted(); LinkedNode item; LinkedNode slot = null; lock (this) { item = waitingPuts.Deq(); if (item == null) { waitingTakes.Enq(slot = new LinkedNode()); } } if (item != null) { lock (item) { Object x = item.Value; if (x != Cancelled) { item.Value = null; item.Next = null; Monitor.Pulse(item); return(x); } } } else { lock (slot) { try { for (; ;) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; return(x); } else { Monitor.Wait(slot); } } } catch (ThreadInterruptedException ie) { Object x = slot.Value; if (x != null) { slot.Value = null; slot.Next = null; Thread.CurrentThread.Interrupt(); return(x); } else { slot.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// Dequeue /// </summary> /// <returns></returns> protected internal virtual LinkedNode Deq() { LinkedNode p = head; if (p != null && (head = p.Next) == null) last = null; return p; }
/* Offer and poll are just like put and take, except even messier. */ /// <summary> /// <see cref="IPuttable.Offer"/> /// </summary> public virtual bool Offer(Object x, long msecs) { if (x == null) throw new ArgumentException(); long waitTime = msecs; long startTime = 0; // lazily initialize below if needed for (; ; ) { Utils.FailFastIfInterrupted(); LinkedNode slot; LinkedNode item = null; lock (this) { slot = waitingTakes.Deq(); if (slot == null) { if (waitTime <= 0) return false; else waitingPuts.Enq(item = new LinkedNode(x)); } } if (slot != null) { lock (slot) { if (slot.Value != Cancelled) { slot.Value = x; Monitor.Pulse(slot); return true; } } } long now = Utils.CurrentTimeMillis; if (startTime == 0) startTime = now; else waitTime = msecs - (now - startTime); if (item != null) { lock (item) { try { for (; ; ) { if (item.Value == null) return true; if (waitTime <= 0) { item.Value = Cancelled; return false; } Monitor.Wait(item, TimeSpan.FromMilliseconds(waitTime)); waitTime = msecs - (Utils.CurrentTimeMillis - startTime); } } catch (ThreadInterruptedException ie) { if (item.Value == null) { Thread.CurrentThread.Interrupt(); return true; } else { item.Value = Cancelled; throw SystemExtensions.PreserveStackTrace(ie); } } } } } }
/// <summary> /// Enqueue /// </summary> /// <param name="p">node to enqueue</param> protected internal virtual void Enq(LinkedNode p) { if (last == null) last = head = p; else last = last.Next = p; }
/// <summary> Create a queue with the given capacity</summary> /// <exception cref="ArgumentException"> if capacity less or equal to zero /// /// </exception> public BoundedLinkedQueue(int capacity) { if (capacity <= 0) throw new ArgumentException(); capacity_ = capacity; putSidePutPermits_ = capacity; head_ = new LinkedNode(null); last_ = head_; }