/// <summary> /// Releases the lock as an upgradeable reader. /// </summary> internal void ReleaseUpgradeableReaderLock(Task upgrade) { IDisposable cancelFinish = null; List <IDisposable> finishes; lock (SyncObject) { if (upgrade != null) { cancelFinish = _upgradeReaderQueue.TryCancel(upgrade); } _upgradeableReaderKey = null; //Enlightenment.Trace.AsyncReaderWriterLock_LockReleased(this, AsyncReaderWriterLockLockType.UpgradeableReader); --_locksHeld; finishes = ReleaseWaiters(); } if (cancelFinish != null) { cancelFinish.Dispose(); } foreach (var finish in finishes) { finish.Dispose(); } }
/// <summary> /// Grants lock(s) to waiting tasks. This method assumes the sync lock is already held. /// </summary> private List <IDisposable> ReleaseWaiters() { var ret = new List <IDisposable>(); if (_locksHeld == 0) { // Give priority to writers. if (!_writerQueue.IsEmpty) { ret.Add(_writerQueue.Dequeue(_cachedWriterKeyTask.Result)); _locksHeld = -1; return(ret); } // Then to upgradeable readers. if (!_upgradeableReaderQueue.IsEmpty) { _upgradeableReaderKey = new UpgradeableReaderKey(this); ret.Add(_upgradeableReaderQueue.Dequeue(_upgradeableReaderKey)); ++_locksHeld; } // Finally to readers. while (!_readerQueue.IsEmpty) { ret.Add(_readerQueue.Dequeue(_cachedReaderKeyTask.Result)); ++_locksHeld; } return(ret); } // Give priority to upgrading readers. if (_locksHeld == 1) { if (!_upgradeReaderQueue.IsEmpty) { ret.Add(_upgradeReaderQueue.Dequeue(_upgradeableReaderKey._cachedUpgradeKeyTask.Result)); _locksHeld = -1; } } if (_locksHeld > 0) { // If there are current reader locks and waiting writers, then do nothing. if (!_writerQueue.IsEmpty || !_upgradeableReaderQueue.IsEmpty || !_upgradeReaderQueue.IsEmpty) { return(ret); } // If there are current reader locks but no upgradeable reader lock, try to release an upgradeable reader. if (_upgradeableReaderKey == null && !_upgradeableReaderQueue.IsEmpty) { _upgradeableReaderKey = new UpgradeableReaderKey(this); ret.Add(_upgradeableReaderQueue.Dequeue(_upgradeableReaderKey)); } } return(ret); }
private IReadOnlyCollection <IDisposable> ReleaseWaiters() { var waiters = new List <IDisposable>(); if (0 == locksHeld) { if (false == writers.IsEmpty) { waiters.Add(writers.Dequeue(cachedWriterKey.Result)); locksHeld = -1; return(waiters); } if (false == upgradeableReaders.IsEmpty) { upgradeableReaderKey = new UpgradeableReaderKey(this); waiters.Add(upgradeableReaders.Dequeue(upgradeableReaderKey)); locksHeld++; } while (false == readers.IsEmpty) { waiters.Add(readers.Dequeue(cachedReaderKey.Result)); } return(waiters); } if (1 == locksHeld) { if (false == upgradeReaders.IsEmpty) { waiters.Add(upgradeReaders.Dequeue(upgradeableReaderKey.cachedUpgradeKey.Result)); locksHeld = -1; } } if (0 < locksHeld) { if (false == writers.IsEmpty || false == upgradeableReaders.IsEmpty || false == upgradeReaders.IsEmpty) { return(waiters); } if (null == upgradeableReaderKey && false == upgradeableReaders.IsEmpty) { upgradeableReaderKey = new UpgradeableReaderKey(this); waiters.Add(upgradeableReaders.Dequeue(upgradeableReaderKey)); } } return(waiters); }
/// <summary> /// /// </summary> /// <param name="ct"></param> /// <returns></returns> public UpgradeableReaderKey AccquireUpgradeableReaderLock(CancellationToken ct) { Task <UpgradeableReaderKey> task; lock (SyncRoot) { if (0 == locksHeld || (locksHeld > 0 && null == upgradeableReaderKey)) { locksHeld++; upgradeableReaderKey = new UpgradeableReaderKey(this); return(upgradeableReaderKey); } task = upgradeableReaders.Enqueue(SyncRoot, ct); } ReleaseWaitersWhenCanceled(task); return(task.WaitAndUnwrapException()); }
/// <summary> /// Synchronously acquires the lock as a reader with the option to upgrade. Returns a key that can be used to upgrade and downgrade the lock, and releases the lock when disposed. This method may block the calling thread. /// </summary> /// <param name="cancellationToken">The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).</param> /// <returns>A key that can be used to upgrade and downgrade this lock, and releases the lock when disposed.</returns> public UpgradeableReaderKey UpgradeableReaderLock(CancellationToken cancellationToken) { Task <UpgradeableReaderKey> ret; lock (SyncObject) { // If the lock is available, take it immediately. if (_locksHeld == 0 || (_locksHeld > 0 && _upgradeableReaderKey == null)) { ++_locksHeld; _upgradeableReaderKey = new UpgradeableReaderKey(this); return(_upgradeableReaderKey); } // Wait for the lock to become available or cancellation. ret = _upgradeableReaderQueue.Enqueue(SyncObject, cancellationToken); } ReleaseWaitersWhenCanceled(ret); return(ret.WaitAndUnwrapException()); }
/// <summary> /// /// </summary> /// <returns></returns> public AwaitableDisposable <UpgradeableReaderKey> AccquireUpgradeableReaderLockAsync(CancellationToken ct) { Task <UpgradeableReaderKey> task; lock (SyncRoot) { if (0 == locksHeld || (locksHeld > 0 && null == upgradeableReaderKey)) { locksHeld++; upgradeableReaderKey = new UpgradeableReaderKey(this); task = Task.FromResult(upgradeableReaderKey); } else { task = upgradeableReaders.Enqueue(SyncRoot, ct); } } ReleaseWaitersWhenCanceled(task); return(new AwaitableDisposable <UpgradeableReaderKey>(task)); }
internal void ReleaseUpgradeableReaderLock(Task upgrade) { IDisposable cancelFinish = null; IEnumerable <IDisposable> finalizers; lock (SyncRoot) { if (null != upgrade) { cancelFinish = upgradeReaders.TryCancel(upgrade); } upgradeableReaderKey = null; locksHeld--; finalizers = ReleaseWaiters(); } cancelFinish?.Dispose(); foreach (var finalizer in finalizers) { finalizer.Dispose(); } }
/// <summary> /// Asynchronously acquires the lock as a reader with the option to upgrade. Returns a key that can be used to upgrade and downgrade the lock, and releases the lock when disposed. /// </summary> /// <param name="cancellationToken">The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).</param> /// <returns>A key that can be used to upgrade and downgrade this lock, and releases the lock when disposed.</returns> public AwaitableDisposable <UpgradeableReaderKey> UpgradeableReaderLockAsync(CancellationToken cancellationToken) { Task <UpgradeableReaderKey> ret; lock (SyncObject) { // If the lock is available, take it immediately. if (_locksHeld == 0 || (_locksHeld > 0 && _upgradeableReaderKey == null)) { ++_locksHeld; _upgradeableReaderKey = new UpgradeableReaderKey(this); ret = TaskShim.FromResult(_upgradeableReaderKey); } else { // Wait for the lock to become available or cancellation. ret = _upgradeableReaderQueue.Enqueue(SyncObject, cancellationToken); } //Enlightenment.Trace.AsyncReaderWriterLock_TrackLock(this, AsyncReaderWriterLockLockType.UpgradeableReader, ret); } ReleaseWaitersWhenCanceled(ret); return(new AwaitableDisposable <UpgradeableReaderKey>(ret)); }
/// <summary> /// Creates the upgrade key for an upgradeable reader key. /// </summary> /// <param name="key">The upgradeable reader key to downgrade. May not be <c>null</c>.</param> public UpgradeKey(UpgradeableReaderKey key) { _key = key; }
/// <summary> /// Grants lock(s) to waiting tasks. This method assumes the sync lock is already held. /// </summary> private List<IDisposable> ReleaseWaiters() { var ret = new List<IDisposable>(); if (_locksHeld == 0) { // Give priority to writers. if (!_writerQueue.IsEmpty) { ret.Add(_writerQueue.Dequeue(_cachedWriterKeyTask.Result)); _locksHeld = -1; return ret; } // Then to upgradeable readers. if (!_upgradeableReaderQueue.IsEmpty) { _upgradeableReaderKey = new UpgradeableReaderKey(this); ret.Add(_upgradeableReaderQueue.Dequeue(_upgradeableReaderKey)); ++_locksHeld; } // Finally to readers. while (!_readerQueue.IsEmpty) { ret.Add(_readerQueue.Dequeue(_cachedReaderKeyTask.Result)); ++_locksHeld; } return ret; } // Give priority to upgrading readers. if (_locksHeld == 1) { if (!_upgradeReaderQueue.IsEmpty) { ret.Add(_upgradeReaderQueue.Dequeue(_upgradeableReaderKey.CachedUpgradeKeyTask.Result)); _locksHeld = -1; } } if (_locksHeld > 0) { // If there are current reader locks and waiting writers, then do nothing. if (!_writerQueue.IsEmpty || !_upgradeableReaderQueue.IsEmpty || !_upgradeReaderQueue.IsEmpty) { return ret; } // If there are current reader locks but no upgradeable reader lock, try to release an upgradeable reader. if (_upgradeableReaderKey == null && !_upgradeableReaderQueue.IsEmpty) { _upgradeableReaderKey = new UpgradeableReaderKey(this); ret.Add(_upgradeableReaderQueue.Dequeue(_upgradeableReaderKey)); } } return ret; }
/// <summary> /// Releases the lock as an upgradeable reader. /// </summary> internal void ReleaseUpgradeableReaderLock(Task upgrade) { IDisposable cancelFinish = null; List<IDisposable> finishes; lock (SyncObject) { if (upgrade != null) { cancelFinish = _upgradeReaderQueue.TryCancel(upgrade); } _upgradeableReaderKey = null; //Enlightenment.Trace.AsyncReaderWriterLock_LockReleased(this, AsyncReaderWriterLockLockType.UpgradeableReader); --_locksHeld; finishes = ReleaseWaiters(); } cancelFinish?.Dispose(); foreach (var finish in finishes) { finish.Dispose(); } }
/// <summary> /// Asynchronously acquires the lock as a reader with the option to upgrade. Returns a key that can be used to upgrade and downgrade the lock, and releases the lock when disposed. /// </summary> /// <param name="cancellationToken">The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).</param> /// <returns>A key that can be used to upgrade and downgrade this lock, and releases the lock when disposed.</returns> public AwaitableDisposable<UpgradeableReaderKey> UpgradeableReaderLockAsync(CancellationToken cancellationToken) { Task<UpgradeableReaderKey> ret; lock (SyncObject) { // If the lock is available, take it immediately. if (_locksHeld == 0 || (_locksHeld > 0 && _upgradeableReaderKey == null)) { ++_locksHeld; _upgradeableReaderKey = new UpgradeableReaderKey(this); ret = TaskShim.FromResult(_upgradeableReaderKey); } else { // Wait for the lock to become available or cancellation. ret = _upgradeableReaderQueue.Enqueue(SyncObject, cancellationToken); } //Enlightenment.Trace.AsyncReaderWriterLock_TrackLock(this, AsyncReaderWriterLockLockType.UpgradeableReader, ret); } ReleaseWaitersWhenCanceled(ret); return new AwaitableDisposable<UpgradeableReaderKey>(ret); }
/// <summary> /// Synchronously acquires the lock as a reader with the option to upgrade. Returns a key that can be used to upgrade and downgrade the lock, and releases the lock when disposed. This method may block the calling thread. /// </summary> /// <param name="cancellationToken">The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).</param> /// <returns>A key that can be used to upgrade and downgrade this lock, and releases the lock when disposed.</returns> public UpgradeableReaderKey UpgradeableReaderLock(CancellationToken cancellationToken) { Task<UpgradeableReaderKey> ret; lock (SyncObject) { // If the lock is available, take it immediately. if (_locksHeld == 0 || (_locksHeld > 0 && _upgradeableReaderKey == null)) { ++_locksHeld; _upgradeableReaderKey = new UpgradeableReaderKey(this); return _upgradeableReaderKey; } // Wait for the lock to become available or cancellation. ret = _upgradeableReaderQueue.Enqueue(SyncObject, cancellationToken); } ReleaseWaitersWhenCanceled(ret); return ret.WaitAndUnwrapException(); }
public UpgradeKey(UpgradeableReaderKey key) { this.key = key; }