You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

109 regels
3.3 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. namespace MQTTnet.Internal
  6. {
  7. // Inspired from Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/11/building-async-coordination-primitives-part-2-asyncautoresetevent/) and Chris Gillum (https://stackoverflow.com/a/43012490)
  8. public class AsyncAutoResetEvent
  9. {
  10. private readonly LinkedList<TaskCompletionSource<bool>> _waiters = new LinkedList<TaskCompletionSource<bool>>();
  11. private bool _isSignaled;
  12. public AsyncAutoResetEvent() : this(false)
  13. { }
  14. public AsyncAutoResetEvent(bool signaled)
  15. {
  16. _isSignaled = signaled;
  17. }
  18. public Task<bool> WaitOneAsync()
  19. {
  20. return WaitOneAsync(CancellationToken.None);
  21. }
  22. public Task<bool> WaitOneAsync(TimeSpan timeout)
  23. {
  24. return WaitOneAsync(timeout, CancellationToken.None);
  25. }
  26. public Task<bool> WaitOneAsync(CancellationToken cancellationToken)
  27. {
  28. return WaitOneAsync(Timeout.InfiniteTimeSpan, cancellationToken);
  29. }
  30. public async Task<bool> WaitOneAsync(TimeSpan timeout, CancellationToken cancellationToken)
  31. {
  32. cancellationToken.ThrowIfCancellationRequested();
  33. TaskCompletionSource<bool> tcs;
  34. lock (_waiters)
  35. {
  36. if (_isSignaled)
  37. {
  38. _isSignaled = false;
  39. return true;
  40. }
  41. else if (timeout == TimeSpan.Zero)
  42. {
  43. return _isSignaled;
  44. }
  45. else
  46. {
  47. tcs = new TaskCompletionSource<bool>();
  48. _waiters.AddLast(tcs);
  49. }
  50. }
  51. Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)).ConfigureAwait(false);
  52. if (winner == tcs.Task)
  53. {
  54. // The task was signaled.
  55. return true;
  56. }
  57. else
  58. {
  59. // We timed-out; remove our reference to the task.
  60. // This is an O(n) operation since waiters is a LinkedList<T>.
  61. lock (_waiters)
  62. {
  63. _waiters.Remove(tcs);
  64. if (winner.Status == TaskStatus.Canceled)
  65. {
  66. throw new OperationCanceledException(cancellationToken);
  67. }
  68. else
  69. {
  70. throw new TimeoutException();
  71. }
  72. }
  73. }
  74. }
  75. public void Set()
  76. {
  77. TaskCompletionSource<bool> toRelease = null;
  78. lock (_waiters)
  79. {
  80. if (_waiters.Count > 0)
  81. {
  82. // Signal the first task in the waiters list.
  83. toRelease = _waiters.First.Value;
  84. _waiters.RemoveFirst();
  85. }
  86. else if (!_isSignaled)
  87. {
  88. // No tasks are pending
  89. _isSignaled = true;
  90. }
  91. }
  92. toRelease?.SetResult(true);
  93. }
  94. }
  95. }