using System; using System.Linq; using System.Collections.Generic; using System.Collections.Concurrent; using System.Reflection; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using var gate = new SemaphoreSlim(1, 1); var first = await Lease.TakeAsync(gate); Task pending = Lease.TakeAsync(gate).AsTask(); Console.WriteLine($"waiting:{!pending.IsCompleted}"); await first.DisposeAsync(); await first.DisposeAsync(); var second = await pending; Console.WriteLine($"inside:{gate.CurrentCount}"); await second.DisposeAsync(); await second.DisposeAsync(); Console.WriteLine($"final:{gate.CurrentCount}"); sealed class Lease : IAsyncDisposable { private SemaphoreSlim? gate; private Lease(SemaphoreSlim gate) { this.gate = gate; } public static async ValueTask TakeAsync(SemaphoreSlim gate) { await gate.WaitAsync().ConfigureAwait(false); return new Lease(gate); } public ValueTask DisposeAsync() { Interlocked.Exchange(ref gate, null)?.Release(); return ValueTask.CompletedTask; } }