public void Release() { Waiter toFinish = null; lock (_lock) { if (currentPermits + 1 > maxPermits) { throw new ArgumentOutOfRangeException("releases"); } currentPermits += 1; Waiter waiter; while ((waiter = (Waiter)DListNode.FirstEntry(waiters)) != null) { if (Volatile.Read(ref waiter.state) != WAITING) { DListNode.RemoveIfInserted(waiter); continue; } if (waiter.TrySetState(SUCCESS)) { DListNode.RemoveIfInserted(waiter); currentPermits -= 1; toFinish = waiter; break; } } } // finish it outside the lock if (toFinish != null) { // cancel the active cancelers if (toFinish.ctkReg != null) { toFinish.ctkReg.Dispose(); } if (toFinish.timer != null) { toFinish.timer.Dispose(); } toFinish.tcs.SetResult(true); } }
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; } }