AsyncLock
Asynchronous lock.
            
                using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace System.Reactive.Concurrency
{
    [System.Runtime.CompilerServices.NullableContext(1)]
    [System.Runtime.CompilerServices.Nullable(0)]
    public sealed class AsyncLock : IDisposable
    {
        private bool _isAcquired;
        private bool _hasFaulted;
        private readonly object _guard = new object();
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            2,
            0,
            1,
            1,
            2,
            1,
            2
        })]
        private Queue<(Action<Delegate, object> action, Delegate delegate, object state)> _queue;
        public void Wait(Action action)
        {
            if (action == null)
                throw new ArgumentNullException("action");
            Wait(action, delegate(Action closureAction) {
                closureAction();
            });
        }
        internal void Wait<[System.Runtime.CompilerServices.Nullable(2)] TState>(TState state, Action<TState> action)
        {
            if (action == null)
                throw new ArgumentNullException("action");
            Wait(state, action, delegate(Delegate actionObject, object stateObject) {
                ((Action<TState>)actionObject)((TState)stateObject);
            });
        }
        private void Wait([System.Runtime.CompilerServices.Nullable(2)] object state, Delegate delegate, [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            1,
            2
        })] Action<Delegate, object> action)
        {
            lock (_guard) {
                if (_hasFaulted)
                    return;
                if (_isAcquired) {
                    Queue<(Action<Delegate, object>, Delegate, object)> queue = _queue;
                    if (queue == null)
                        queue = (_queue = new Queue<(Action<Delegate, object>, Delegate, object)>());
                    queue.Enqueue((action, delegate, state));
                    return;
                }
                _isAcquired = true;
            }
            while (true) {
                try {
                    action(delegate, state);
                } catch {
                    lock (_guard) {
                        _queue = null;
                        _hasFaulted = true;
                    }
                    throw;
                }
                lock (_guard) {
                    Queue<(Action<Delegate, object>, Delegate, object)> queue2 = _queue;
                    if (queue2 == null || queue2.Count == 0) {
                        _isAcquired = false;
                        return;
                    }
                    (Action<Delegate, object>, Delegate, object) valueTuple = queue2.Dequeue();
                    action = valueTuple.Item1;
                    delegate = valueTuple.Item2;
                    state = valueTuple.Item3;
                }
            }
        }
        public void Dispose()
        {
            lock (_guard) {
                _queue = null;
                _hasFaulted = true;
            }
        }
    }
}