public void Release() { Waiter <Data> toFinish = null; lock (_lock) { if (currentPermits + 1 > maxPermits) { throw new ArgumentOutOfRangeException("releases"); } currentPermits += 1; Waiter <Data> waiter; while ((waiter = (Waiter <Data>)DListNode.FirstEntry(waiters)) != null) { if (Volatile.Read(ref waiter.state) != WaiterState.WAITING) { // Shouldn't already be on the queue, ensure it is removed DListNode.RemoveIfInserted(waiter); continue; } if (waiter.TrySetStateAndUnlink(WaiterState.SUCCESS)) { currentPermits -= 1; // queue node for further processing outside the lock waiter.prev = toFinish; toFinish = waiter; break; } } } // finish the stack of satisfied requests while (toFinish != null) { toFinish.OnSuccess(); toFinish = (Waiter <Data>)toFinish.prev; } }
//--------------------------------------------------------------------- // Synchronous //-- public bool WaitEx(int timeout, CancellationToken ctk) { bool interrupted = false; Waiter <Data> waiter = null; bool ownsTheWaiter = false; lock (_lock) { if (currentPermits > 0) { currentPermits -= 1; return(true); } // if the current thread must block, check immediate cancelers if (timeout == 0) { return(false); } ctk.ThrowIfCancellationRequested(); // create a synchronous waiter node and insert it in the wait queue waiter = new SyncWaiter <Data>(new Data(), ctk, SyncUnlink); DListNode.AddLast(waiters, waiter); waiter.Enable(); // wrap timeout value with timeout holder, in order to support timeout adjust TimeoutHolder th = new TimeoutHolder(timeout); // wait until the request is staisfied, timeout expires or cancellation do { try { if ((timeout = th.Value) == 0) { ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.TIMED_OUT); break; } // wait on the monitor's condition variable MonitorEx.Wait(_lock, waiter, timeout); } catch (ThreadInterruptedException) { interrupted = true; ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.INTERRUPTED); break; } } while (waiter.State == WaiterState.WAITING); } // this processing is private of the current thread, so we can do it without // owning the lock. if (ownsTheWaiter) { waiter.CancelCancellation(); } if (waiter.State == WaiterState.INTERRUPTED) { throw new ThreadInterruptedException(); } if (interrupted) { Thread.CurrentThread.Interrupt(); } if (waiter.State == WaiterState.CANCELED) { throw new OperationCanceledException(ctk); } return(waiter.State == WaiterState.SUCCESS); }