using System; using System.Threading; using System.Threading.Tasks; namespace MQTTnet.Internal { // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) public sealed class AsyncLock : IDisposable { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly Task _releaser; public AsyncLock() { _releaser = Task.FromResult((IDisposable)new Releaser(this)); } public Task LockAsync(CancellationToken cancellationToken) { Task wait = _semaphore.WaitAsync(cancellationToken); return wait.IsCompleted ? _releaser : wait.ContinueWith((_, state) => (IDisposable)state, _releaser.Result, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public void Dispose() { _semaphore?.Dispose(); } private sealed class Releaser : IDisposable { private readonly AsyncLock _toRelease; internal Releaser(AsyncLock toRelease) { _toRelease = toRelease; } public void Dispose() { _toRelease._semaphore.Release(); } } } }