public virtual void DoWait(IQueuedSync sync) { lock (this) { if (!sync.Recheck(this)) { try { while (_waiting) { Monitor.Wait(this); } } catch (ThreadInterruptedException ex) { if (_waiting) { // no notification _waiting = false; // invalidate for the signaller throw SystemExtensions.PreserveStackTrace(ex); } // thread was interrupted after it was notified Thread.CurrentThread.Interrupt(); return; } } } }
/// <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); } }
public override void LockInterruptibly() { Thread caller = Thread.CurrentThread; lock (this) { if (GetHold(caller)) { return; } try { do { Monitor.Wait(this); } while (_owner != null); _owner = caller; _holds = 1; return; } catch (ThreadInterruptedException e) { if (_owner == null) { Monitor.Pulse(this); } throw SystemExtensions.PreserveStackTrace(e); } } }
/** * 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(); }
public virtual bool AwaitUntil(DateTime deadline) { int holdCount = _lock.HoldCount; if (holdCount == 0) { throw new SynchronizationLockException(); } if ((deadline.Subtract(DateTime.UtcNow)).Ticks <= 0) { return(false); } // This requires sleep(0) to implement in .Net, too expensive! // if (Thread.interrupted()) throw new InterruptedException(); try { lock (this) { for (int i = holdCount; i > 0; i--) { _lock.Unlock(); } try { // .Net has DateTime precision issue so we need to retry. TimeSpan durationToWait; while ((durationToWait = deadline.Subtract(DateTime.UtcNow)).Ticks > 0) { // .Net implementation is different than backport 3.1 // by taking advantage of the return value from Monitor.Wait. if (Monitor.Wait(this, durationToWait)) { return(true); } } } catch (ThreadInterruptedException e) { Monitor.Pulse(this); throw SystemExtensions.PreserveStackTrace(e); } } } finally { for (int i = holdCount; i > 0; i--) { _lock.Lock(); } } return(false); }
/// <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 } } }
public virtual bool DoTimedWait(IQueuedSync sync, TimeSpan duration) { lock (this) { if (sync.Recheck(this) || !_waiting) { return(true); } if (duration.Ticks <= 0) { _waiting = false; return(false); } DateTime deadline = DateTime.UtcNow.Add(duration); try { for (;;) { Monitor.Wait(this, duration); if (!_waiting) // definitely signalled { return(true); } duration = deadline.Subtract(DateTime.UtcNow); if (duration.Ticks <= 0) // time out { _waiting = false; return(false); } } } catch (ThreadInterruptedException ex) { if (_waiting) // no notification { _waiting = false; // invalidate for the signaller throw SystemExtensions.PreserveStackTrace(ex); } // thread was interrupted after it was notified Thread.CurrentThread.Interrupt(); return(true); } } }
/// <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); } } }
public override bool TryLock(TimeSpan durationToWait) { Thread caller = Thread.CurrentThread; lock (this) { if (GetHold(caller)) { return(true); } if (durationToWait.Ticks <= 0) { return(false); } DateTime deadline = DateTime.UtcNow.Add(durationToWait); try { for (;;) { Monitor.Wait(this, durationToWait); if (_owner == null) { _owner = caller; _holds = 1; return(true); } durationToWait = deadline.Subtract(DateTime.UtcNow); if (durationToWait.Ticks <= 0) { return(false); } } } catch (ThreadInterruptedException e) { if (_owner == null) { Monitor.Pulse(this); } 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 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); }
/// <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 } } }
public virtual bool Await(TimeSpan durationToWait) { int holdCount = _lock.HoldCount; if (holdCount == 0) { throw new SynchronizationLockException(); } // This requires sleep(0) to implement in .Net, too expensive! // if (Thread.interrupted()) throw new InterruptedException(); try { lock (this) { for (int i = holdCount; i > 0; i--) { _lock.Unlock(); } try { // .Net implementation is a little different than backport 3.1 // by taking advantage of the return value from Monitor.Wait. return((durationToWait.Ticks > 0) && Monitor.Wait(this, durationToWait)); } catch (ThreadInterruptedException e) { Monitor.Pulse(this); throw SystemExtensions.PreserveStackTrace(e); } } } finally { for (int i = holdCount; i > 0; i--) { _lock.Lock(); } } }
public virtual void Await() { int holdCount = _lock.HoldCount; if (holdCount == 0) { throw new SynchronizationLockException(); } // This requires sleep(0) to implement in .Net, too expensive! // if (Thread.interrupted()) throw new InterruptedException(); try { lock (this) { for (int i = holdCount; i > 0; i--) { _lock.Unlock(); } try { Monitor.Wait(this); } catch (ThreadInterruptedException e) { Monitor.Pulse(this); throw SystemExtensions.PreserveStackTrace(e); } } } finally { for (int i = holdCount; i > 0; i--) { _lock.Lock(); } } }
/// <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); } } } } } }
/* * 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.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> Main barrier code, covering the various policies.</summary> private int DoWait(bool timed, TimeSpan duration) { using (_lock.Lock()) { Generation currentGeneration = _generation; if (currentGeneration.isBroken) { throw new BrokenBarrierException(); } int index = --_count; if (index == 0) { bool ranAction = false; try { Action command = _barrierCommand; if (command != null) { command(); } ranAction = true; NextGeneration(); return(0); } finally { if (!ranAction) { BreakBarrier(); } } } // loop until tripped, broken, interrupted, or timed out DateTime deadline = DateTime.UtcNow.Add(duration); for (;;) { try { if (!timed) { _trip.Await(); } else if (duration.Ticks > 0) { _trip.Await(duration); duration = deadline.Subtract(DateTime.UtcNow); } } catch (ThreadInterruptedException e) { if (currentGeneration == _generation && !currentGeneration.isBroken) { BreakBarrier(); throw SystemExtensions.PreserveStackTrace(e); } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.CurrentThread.Interrupt(); } } if (currentGeneration.isBroken) { throw new BrokenBarrierException(); } if (currentGeneration != _generation) { return(index); } if (timed && duration.Ticks <= 0) { BreakBarrier(); throw new TimeoutException(); } } } }