private void DoWait(Action <WaitNode> action) { int holdCount = Lock.HoldCount; if (holdCount == 0) { throw new SynchronizationLockException(); } WaitNode n = new WaitNode(); _wq.Enqueue(n); for (int i = holdCount; i > 0; i--) { Lock.Unlock(); } try { action(n); } finally { for (int i = holdCount; i > 0; i--) { Lock.Lock(); } } }
/// <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> /// Inserts the specified element into this queue, waiting if necessary /// another thread to receive it. /// </summary> /// <param name="element">the element to add</param> /// <exception cref="ThreadInterruptedException"> /// if interrupted while waiting. /// </exception> public override void Put(T element) { 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 { node.WaitForTake(); return; } catch (ThreadInterruptedException tie) { UnlinkCancelledProducer(node); throw SystemExtensions.PreserveStackTrace(tie); } } else if (node.SetItem(element)) { return; } // else consumer cancelled, so retry } }
public bool Recheck(WaitNode node) { var caller = Thread.CurrentThread; lock (this) { if (GetHold(caller)) { return(true); } _wq.Enqueue(node); return(false); } }