/// <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);
        }
示例#3
0
        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);
        }
示例#4
0
        /// <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());
        }
示例#6
0
        /// <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));
        }
示例#7
0
        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));
        }
示例#9
0
 /// <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;
 }
示例#10
0
        /// <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;
        }
示例#11
0
 /// <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();
     }
 }
示例#12
0
        /// <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);
        }
示例#13
0
        /// <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();
        }
示例#14
0
 public UpgradeKey(UpgradeableReaderKey key)
 {
     this.key = key;
 }
示例#15
0
 /// <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;
 }