AsyncLock.cs 2.5 KB

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