//**************************************** private void Cancel(KeyedLockInstance instance) { // Retrieve the current lock state while (_Locks.TryGetValue(instance.Key !, out var OldQueue)) { // Can get no results (or no queue at all) if // - someone releases while we cancel and Release removes us from the queue // - we disposed if (OldQueue.IsEmpty) { return; } var NewQueue = OldQueue.Remove(instance); if (ReferenceEquals(OldQueue, NewQueue)) { return; } // Apply the changes to the lock queue if (_Locks.TryUpdate(instance.Key !, NewQueue, OldQueue)) { return; } // Someone modified the lock queue, probably a new waiter, so retry } }
private void Release(TKey key) { // Retrieve the current lock state while (_Locks.TryGetValue(key, out var OldQueue)) { for (; ;) { // If it's empty, there's no waiters or they've all cancelled if (OldQueue.IsEmpty) { // Release the lock if (((IDictionary <TKey, ImmutableList <KeyedLockInstance> >)_Locks).Remove(new KeyValuePair <TKey, ImmutableList <KeyedLockInstance> >(key, OldQueue))) { // If we're disposing and the final held lock, complete disposal if (_Disposer != null && _Locks.IsEmpty) { _Disposer.SwitchToComplete(); } return; } // Someone modified the lock queue, probably a new waiter, so retry break; } // Remove the next waiter from the queue var NextWaiter = OldQueue[0]; var NewQueue = OldQueue.RemoveAt(0); // Apply the changes to the lock queue if (!_Locks.TryUpdate(key, NewQueue, OldQueue)) { // Someone modified the lock queue, probably a new waiter, so retry break; } // Try to activate the waiter if (NextWaiter.TrySwitchToCompleted()) { return; } // Waiter has cancelled. Try and pull another off the queue OldQueue = NewQueue; } } // May get here if we dispose Debug.Fail("Lock was released but not held"); }