| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 | // Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the Apache 2.0 License.// See the LICENSE file in the project root for more information. using System.Diagnostics;using System.Threading.Tasks;namespace System.Threading{    public sealed class AsyncLock    {        private readonly object gate = new object();        private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);        private readonly AsyncLocal<int> recursionCount = new AsyncLocal<int>();        public Task<Releaser> LockAsync()        {            var shouldAcquire = false;            lock (gate)            {                if (recursionCount.Value == 0)                {                    shouldAcquire = true;                    recursionCount.Value = 1;                }                else                {                    recursionCount.Value++;                }            }            if (shouldAcquire)            {                return semaphore.WaitAsync().ContinueWith(_ => new Releaser(this));            }            return Task.FromResult(new Releaser(this));        }        private void Release()        {            lock (gate)            {                Debug.Assert(recursionCount.Value > 0);                if (--recursionCount.Value == 0)                {                    semaphore.Release();                }            }        }        public struct Releaser : IDisposable        {            private readonly AsyncLock parent;            public Releaser(AsyncLock parent) => this.parent = parent;            public void Dispose() => parent.Release();        }    }}
 |