/// <summary> /// Retrieves and removes the head of this queue, waiting up to the /// specified wait time if necessary for an element to become available. /// </summary> /// <param name="element"> /// Set to the head of this queue. <c>default(T)</c> if queue is empty. /// </param> /// <param name="duration">How long to wait before giving up.</param> /// <returns> /// <c>false</c> if the queue is still empty after waited for the time /// specified by the <paramref name="duration"/>. Otherwise <c>true</c>. /// </returns> public override bool Poll(TimeSpan duration, out T element) { DateTime deadline = WaitTime.Deadline(duration); using (_lock.LockInterruptibly()) { while (!_wrapped.Poll(out element)) { if (duration.Ticks <= 0) { element = default(T); return(false); } try { _notEmptyCondition.Await(WaitTime.Cap(duration)); duration = deadline.Subtract(DateTime.UtcNow); } catch (ThreadInterruptedException e) { _notEmptyCondition.Signal(); throw SystemExtensions.PreserveStackTrace(e); } } _notFullCondition.Signal(); return(true); } }
/** * Tries to cancel on interrupt; if so rethrowing, * else setting interrupt state * * PRE: lock owned */ private void CheckCancellationOnInterrupt(ThreadInterruptedException ie) { if (_state == 0) { _state = Cancel; Monitor.Pulse(this); throw SystemExtensions.PreserveStackTrace(ie); } Thread.CurrentThread.Interrupt(); }
/// <summary> /// Inserts the specified element into this queue, waiting if necessary /// for space to become available. /// </summary> /// <remarks> /// <see cref="Break"/> the queue will cause a waiting <see cref="TryPut"/> /// to returned <c>false</c>. This is very useful to indicate that the /// consumer is stopped or going to stop so that the producer should not /// put more items into the queue. /// </remarks> /// <param name="element">the element to add</param> /// <returns> /// <c>true</c> if succesfully and <c>false</c> if queue <see cref="IsBroken"/>. /// </returns> /// <exception cref="ThreadInterruptedException"> /// if interrupted while waiting. /// </exception> public virtual bool TryPut(T element) { int tempCount; lock (_putLock) { /* * Note that count is used in wait guard even though it is * not protected by lock. This works because count can * only decrease at this point (all other puts are shut * out by lock), and we (or some other waiting put) are * signaled if it ever changes from capacity. Similarly * for all other uses of count in other wait guards. */ if (_isBroken) { return(false); } try { while (_activeCount == _capacity) { Monitor.Wait(_putLock); if (_isBroken) { return(false); } } } catch (ThreadInterruptedException e) { Monitor.Pulse(_putLock); throw SystemExtensions.PreserveStackTrace(e); } Insert(element); lock (this) { tempCount = _activeCount++; } if (tempCount + 1 < _capacity) { Monitor.Pulse(_putLock); } } if (tempCount == 0) { SignalNotEmpty(); } return(true); }
/// <summary> /// Retrieves and removes the head of this queue, waiting up to the /// specified wait time if necessary for another thread to insert it. /// </summary> /// <param name="element"> /// Set to the head of this queue. <c>default(T)</c> if queue is empty. /// </param> /// <param name="duration">How long to wait before giving up.</param> /// <returns> /// <c>false</c> if the queue is still empty after waited for the time /// specified by the <paramref name="duration"/>. Otherwise <c>true</c>. /// </returns> public override bool Poll(TimeSpan duration, out T element) { for (; ;) { Node node; bool mustWait; //if (Thread.interrupted()) throw new InterruptedException(); using (_qlock.Lock()) { node = _waitingProducers.Dequeue(); mustWait = (node == null); if (mustWait) { node = _waitingConsumers.Enqueue(default(T)); } } if (mustWait) { try { T x; bool success = node.WaitForPut(duration, out x); if (!success) { UnlinkCancelledConsumer(node); } element = x; return(success); } catch (ThreadInterruptedException e) { UnlinkCancelledConsumer(node); throw SystemExtensions.PreserveStackTrace(e); } } else { T x; if (node.GetItem(out x)) { element = x; return(true); } // else cancelled, so retry } } }
/// <summary> /// Inserts the specified element into this queue, waiting up to the /// specified wait time if necessary for space to become available. /// </summary> /// <param name="element">the element to add</param> /// <param name="duration">how long to wait before giving up</param> /// <returns> <c>true</c> if successful, or <c>false</c> if /// the specified waiting time elapses before space is available /// </returns> /// <exception cref="System.InvalidOperationException"> /// If the element cannot be added at this time due to capacity restrictions. /// </exception> /// <exception cref="ThreadInterruptedException"> /// if interrupted while waiting. /// </exception> public override bool Offer(T element, TimeSpan duration) { DateTime deadline = WaitTime.Deadline(duration); int tempCount; lock (_putLock) { for (; ;) { if (_isBroken) { return(false); } if (_activeCount < _capacity) { Insert(element); lock (this) { tempCount = _activeCount++; } if (tempCount + 1 < _capacity) { Monitor.Pulse(_putLock); } break; } if (duration.Ticks <= 0) { return(false); } try { Monitor.Wait(_putLock, WaitTime.Cap(duration)); duration = deadline.Subtract(DateTime.UtcNow); } catch (ThreadInterruptedException e) { Monitor.Pulse(_putLock); throw SystemExtensions.PreserveStackTrace(e); } } } if (tempCount == 0) { SignalNotEmpty(); } return(true); }
/// <summary> /// Retrieves and removes the head of this queue, waiting up to the /// specified wait time if necessary for an element to become available. /// </summary> /// <param name="element"> /// Set to the head of this queue. <c>default(T)</c> if queue is empty. /// </param> /// <param name="duration">How long to wait before giving up.</param> /// <returns> /// <c>false</c> if the queue is still empty after waited for the time /// specified by the <paramref name="duration"/>. Otherwise <c>true</c>. /// </returns> public override bool Poll(TimeSpan duration, out T element) { DateTime deadline = WaitTime.Deadline(duration); T x; int c; lock (_takeLock) { for (; ;) { if (_activeCount > 0) { x = Extract(); lock (this) { c = _activeCount--; } if (c > 1) { Monitor.Pulse(_takeLock); } break; } if (duration.Ticks <= 0 || _isBroken) { element = default(T); return(false); } try { Monitor.Wait(_takeLock, WaitTime.Cap(duration)); duration = deadline.Subtract(DateTime.UtcNow); } catch (ThreadInterruptedException e) { Monitor.Pulse(_takeLock); throw SystemExtensions.PreserveStackTrace(e); } } } if (c == _capacity) { SignalNotFull(); } element = x; return(true); }
/// <summary> /// Inserts the specified element into this queue, waiting if necessary /// for space to become available. /// </summary> /// <param name="element">the element to add</param> /// <exception cref="System.ArgumentNullException"> /// If the specified element is <see langword="null"/> and this queue /// does not permit <see langword="null"/> elements. /// </exception> /// <exception cref="System.ArgumentException"> /// If some property of the supplied <paramref name="element"/> prevents /// it from being added to this queue. /// </exception> public override void Put(T element) { using (_lock.LockInterruptibly()) { try { while (!_wrapped.Offer(element)) { _notFullCondition.Await(); } _notEmptyCondition.Signal(); } catch (ThreadInterruptedException e) { _notFullCondition.Signal(); throw SystemExtensions.PreserveStackTrace(e); } } }
/// <summary> /// Inserts the specified element into this queue, waiting up to the /// specified wait time if necessary for another thread to receive it. /// </summary> /// <param name="element">The element to add.</param> /// <param name="duration">How long to wait before giving up.</param> /// <returns> /// <see langword="true"/> if successful, or <see langword="false"/> if /// the specified waiting time elapses before space is available. /// </returns> /// <exception cref="ThreadInterruptedException"> /// if interrupted while waiting. /// </exception> public override bool Offer(T element, TimeSpan duration) { for (; ;) { Node node; bool mustWait; //if (Thread.interrupted()) throw new InterruptedException(); using (_qlock.Lock()) { node = _waitingConsumers.Dequeue(); mustWait = (node == null); if (mustWait) { node = _waitingProducers.Enqueue(element); } } if (mustWait) { try { bool x = node.WaitForTake(duration); if (!x) { UnlinkCancelledProducer(node); } return(x); } catch (ThreadInterruptedException tie) { UnlinkCancelledProducer(node); throw SystemExtensions.PreserveStackTrace(tie); } } else if (node.SetItem(element)) { return(true); } // else consumer cancelled, so retry } }
/// <summary> /// Retrieves and removes the head of this queue, waiting if necessary /// until another thread inserts it. /// </summary> /// <returns> the head of this queue</returns> /// <exception cref="ThreadInterruptedException"> /// if interrupted while waiting. /// </exception> public override T Take() { for (; ;) { Node node; bool mustWait; //if (Thread.interrupted()) throw new InterruptedException(); using (_qlock.Lock()) { node = _waitingProducers.Dequeue(); mustWait = (node == null); if (mustWait) { node = _waitingConsumers.Enqueue(default(T)); } } if (mustWait) { try { return(node.WaitForPut()); } catch (ThreadInterruptedException e) { UnlinkCancelledConsumer(node); throw SystemExtensions.PreserveStackTrace(e); } } else { T x; if (node.GetItem(out x)) { return(x); } // else cancelled, so retry } } }
/// <summary> /// Retrieves and removes the head of this queue, waiting if necessary /// until an element becomes available. /// </summary> /// <returns> the head of this queue</returns> public override T Take() { using (_lock.LockInterruptibly()) { try { T element; while (!_wrapped.Poll(out element)) { _notEmptyCondition.Await(); } _notFullCondition.Signal(); return(element); } catch (ThreadInterruptedException e) { _notEmptyCondition.Signal(); throw SystemExtensions.PreserveStackTrace(e); } } }
/// <summary> /// Retrieves and removes the head of this queue, waiting if necessary /// until an element becomes available. /// </summary> /// <remarks> /// <see cref="Break"/> the queue will cause a waiting <see cref="TryTake"/> /// to returned <c>false</c>. This is very useful to indicate that the /// producer is stopped so that the producer should stop waiting for /// element from queu. /// </remarks> /// <param name="element"> /// The head of this queue if successful. /// </param> /// <returns> /// <c>true</c> if succesfully and <c>false</c> if queue is empty and /// <see cref="IsBroken">closed</see>. /// </returns> public virtual bool TryTake(out T element) { T x; int tempCount; lock (_takeLock) { try { while (_activeCount == 0) { if (_isBroken) { element = default(T); return(false); } Monitor.Wait(_takeLock); } } catch (ThreadInterruptedException e) { Monitor.Pulse(_takeLock); throw SystemExtensions.PreserveStackTrace(e); } x = Extract(); lock (this) { tempCount = _activeCount--; } if (tempCount > 1) { Monitor.Pulse(_takeLock); } } if (tempCount == _capacity) { SignalNotFull(); } element = x; return(true); }