AsyncLock.cs 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. namespace MQTTnet.Internal
  5. {
  6. // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/)
  7. public class AsyncLock : IDisposable
  8. {
  9. private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
  10. private readonly Task<IDisposable> _releaser;
  11. public AsyncLock()
  12. {
  13. _releaser = Task.FromResult((IDisposable)new Releaser(this));
  14. }
  15. public Task<IDisposable> WaitAsync()
  16. {
  17. return WaitAsync(CancellationToken.None);
  18. }
  19. public Task<IDisposable> WaitAsync(CancellationToken cancellationToken)
  20. {
  21. var task = _semaphore.WaitAsync(cancellationToken);
  22. if (task.Status == TaskStatus.RanToCompletion)
  23. {
  24. return _releaser;
  25. }
  26. return task.ContinueWith(
  27. (_, state) => (IDisposable)state,
  28. _releaser.Result,
  29. cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
  30. }
  31. public void Dispose()
  32. {
  33. _semaphore?.Dispose();
  34. }
  35. private class Releaser : IDisposable
  36. {
  37. private readonly AsyncLock _toRelease;
  38. internal Releaser(AsyncLock toRelease)
  39. {
  40. _toRelease = toRelease;
  41. }
  42. public void Dispose()
  43. {
  44. _toRelease._semaphore.Release();
  45. }
  46. }
  47. }
  48. }