/// <summary>
        /// Asynchronously enters the lock in read mode and returns a <see cref="IDisposableLock"/> that
        /// will release the lock when disposed.
        /// </summary>
        /// <param name="lockInstance">The <see cref="AsyncReaderWriterLockSlim"/> instance.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
        /// <returns>A task that will complete with a <see cref="IDisposableLock"/> when the lock has been entered,
        /// which will release the lock when disposed.</returns>
        /// <exception cref="OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public static async Task <IDisposableLock> GetReadLockAsync(
            this AsyncReaderWriterLockSlim lockInstance,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            await lockInstance.EnterReadLockAsync(cancellationToken);

            return(new ActionDisposableLock(lockInstance.ExitReadLock, lockInstance, false));
        }
        /// <summary>
        /// Enters the lock in write mode.
        /// </summary>
        /// <param name="lockInstance">The <see cref="AsyncReaderWriterLockSlim"/> instance.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
        /// <returns>A <see cref="IDisposableLock"/> that will release the lock when disposed.</returns>
        /// <exception cref="OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public static IDisposableLock GetWriteLock(
            this AsyncReaderWriterLockSlim lockInstance,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            lockInstance.EnterWriteLock(cancellationToken);

            return(new ActionDisposableLock(lockInstance.ExitWriteLock, lockInstance, true));
        }
 public ActionDisposableLock(
     Action action,
     AsyncReaderWriterLockSlim lockOrigin,
     bool isWriteLock)
 {
     this.action      = action;
     this.lockOrigin  = lockOrigin;
     this.isWriteLock = isWriteLock;
 }
        /// <summary>
        /// Tries to asynchronously enter the lock in read mode, with an optional integer time-out.
        /// </summary>
        /// <param name="lockInstance">The <see cref="AsyncReaderWriterLockSlim"/> instance.</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or -1
        /// (<see cref="Timeout.Infinite"/>) to wait indefinitely.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
        /// <returns>A task that will complete with a <see cref="IDisposableLock"/> that will release the lock
        /// when disposed if the lock could be entered, or with <c>null</c> otherwise.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number
        /// other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public static async Task <IDisposableLock> TryGetReadLockAsync(
            this AsyncReaderWriterLockSlim lockInstance,
            int millisecondsTimeout,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            bool returnValue = await lockInstance.TryEnterReadLockAsync(
                millisecondsTimeout, cancellationToken);

            if (returnValue)
            {
                return(new ActionDisposableLock(lockInstance.ExitReadLock, lockInstance, false));
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// Tries to enter the lock in write mode, with an optional integer time-out.
        /// </summary>
        /// <param name="lockInstance">The <see cref="AsyncReaderWriterLockSlim"/> instance.</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or -1
        /// (<see cref="Timeout.Infinite"/>) to wait indefinitely.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
        /// <returns>A <see cref="IDisposableLock"/> that will release the lock when disposed if the lock
        /// could be entered, or <c>null</c> otherwise.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number
        /// other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public static IDisposableLock TryGetWriteLock(
            this AsyncReaderWriterLockSlim lockInstance,
            int millisecondsTimeout,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            bool returnValue = lockInstance.TryEnterWriteLock(
                millisecondsTimeout, cancellationToken);

            if (returnValue)
            {
                return(new ActionDisposableLock(lockInstance.ExitWriteLock, lockInstance, true));
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// Downgrades the lock from write mode to read mode.
        /// </summary>
        /// <param name="lockInstance">The <see cref="AsyncReaderWriterLockSlim"/> instance.</param>
        /// <param name="readLock">The <see cref="IDisposableLock"/> which should be downgraded.</param>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public static void DowngradeWriteLockToReadLock(
            this AsyncReaderWriterLockSlim lockInstance,
            IDisposableLock readLock)
        {
            if (readLock == null)
            {
                throw new ArgumentNullException(nameof(readLock));
            }

            var myReadLock = readLock as ActionDisposableLock;

            if (myReadLock == null || myReadLock.LockOrigin != lockInstance ||
                !myReadLock.IsWriteLock || myReadLock.IsDisposed)
            {
                throw new ArgumentException();
            }

            // Downgrade the lock.
            lockInstance.DowngradeWriteLockToReadLock();

            // Now mark the lock as being a read lock.
            myReadLock.IsWriteLock = false;
        }