AsyncLock.cs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. namespace System.Reactive.Concurrency
  6. {
  7. /// <summary>
  8. /// Asynchronous lock.
  9. /// </summary>
  10. public sealed class AsyncLock : IDisposable
  11. {
  12. private readonly Queue<Action> queue = new Queue<Action>();
  13. private bool isAcquired = false;
  14. private bool hasFaulted = false;
  15. /// <summary>
  16. /// Queues the action for execution. If the caller acquires the lock and becomes the owner,
  17. /// the queue is processed. If the lock is already owned, the action is queued and will get
  18. /// processed by the owner.
  19. /// </summary>
  20. /// <param name="action">Action to queue for execution.</param>
  21. /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
  22. public void Wait(Action action)
  23. {
  24. if (action == null)
  25. throw new ArgumentNullException(nameof(action));
  26. var isOwner = false;
  27. lock (queue)
  28. {
  29. if (!hasFaulted)
  30. {
  31. queue.Enqueue(action);
  32. isOwner = !isAcquired;
  33. isAcquired = true;
  34. }
  35. }
  36. if (isOwner)
  37. {
  38. while (true)
  39. {
  40. var work = default(Action);
  41. lock (queue)
  42. {
  43. if (queue.Count > 0)
  44. work = queue.Dequeue();
  45. else
  46. {
  47. isAcquired = false;
  48. break;
  49. }
  50. }
  51. try
  52. {
  53. work();
  54. }
  55. catch
  56. {
  57. lock (queue)
  58. {
  59. queue.Clear();
  60. hasFaulted = true;
  61. }
  62. throw;
  63. }
  64. }
  65. }
  66. }
  67. /// <summary>
  68. /// Clears the work items in the queue and drops further work being queued.
  69. /// </summary>
  70. public void Dispose()
  71. {
  72. lock (queue)
  73. {
  74. queue.Clear();
  75. hasFaulted = true;
  76. }
  77. }
  78. }
  79. }