CountdownEvent.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // CountdownEvent.cs
  2. //
  3. // Copyright (c) 2008 Jérémie "Garuma" Laval
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. //
  24. #if NET_4_0 || MOBILE
  25. using System;
  26. namespace System.Threading
  27. {
  28. [System.Diagnostics.DebuggerDisplayAttribute ("Initial Count={InitialCount}, Current Count={CurrentCount}")]
  29. public class CountdownEvent : IDisposable
  30. {
  31. int initialCount;
  32. int initial;
  33. ManualResetEventSlim evt = new ManualResetEventSlim (false);
  34. public CountdownEvent (int initialCount)
  35. {
  36. if (initialCount < 0)
  37. throw new ArgumentOutOfRangeException ("initialCount is negative");
  38. this.initial = this.initialCount = initialCount;
  39. }
  40. public bool Signal ()
  41. {
  42. return Signal (1);
  43. }
  44. public bool Signal (int signalCount)
  45. {
  46. if (signalCount <= 0)
  47. throw new ArgumentOutOfRangeException ("signalCount");
  48. Action<int> check = delegate (int value) {
  49. if (value < 0)
  50. throw new InvalidOperationException ("the specified initialCount is larger that CurrentCount");
  51. };
  52. int newValue;
  53. if (!ApplyOperation (-signalCount, check, out newValue))
  54. throw new InvalidOperationException ("The event is already set");
  55. if (newValue == 0) {
  56. evt.Set ();
  57. return true;
  58. }
  59. return false;
  60. }
  61. public void AddCount ()
  62. {
  63. AddCount (1);
  64. }
  65. public void AddCount (int signalCount)
  66. {
  67. if (signalCount < 0)
  68. throw new ArgumentOutOfRangeException ("signalCount");
  69. if (!TryAddCount (signalCount))
  70. throw new InvalidOperationException ("The event is already set");
  71. }
  72. public bool TryAddCount ()
  73. {
  74. return TryAddCount (1);
  75. }
  76. public bool TryAddCount (int signalCount)
  77. {
  78. if (signalCount < 0)
  79. throw new ArgumentOutOfRangeException ("signalCount");
  80. return ApplyOperation (signalCount, null);
  81. }
  82. bool ApplyOperation (int num, Action<int> doCheck)
  83. {
  84. int temp;
  85. return ApplyOperation (num, doCheck, out temp);
  86. }
  87. bool ApplyOperation (int num, Action<int> doCheck, out int newValue)
  88. {
  89. int oldCount;
  90. newValue = 0;
  91. do {
  92. oldCount = initialCount;
  93. if (oldCount == 0)
  94. return false;
  95. newValue = oldCount + num;
  96. if (doCheck != null)
  97. doCheck (newValue);
  98. } while (Interlocked.CompareExchange (ref initialCount, newValue, oldCount) != oldCount);
  99. return true;
  100. }
  101. public void Wait ()
  102. {
  103. evt.Wait ();
  104. }
  105. public void Wait (CancellationToken cancellationToken)
  106. {
  107. evt.Wait (cancellationToken);
  108. }
  109. public bool Wait (int millisecondsTimeout)
  110. {
  111. return evt.Wait (millisecondsTimeout);
  112. }
  113. public bool Wait(TimeSpan timeout)
  114. {
  115. return evt.Wait (timeout);
  116. }
  117. public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
  118. {
  119. return evt.Wait (millisecondsTimeout, cancellationToken);
  120. }
  121. public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
  122. {
  123. return evt.Wait (timeout, cancellationToken);
  124. }
  125. public void Reset ()
  126. {
  127. Reset (initial);
  128. }
  129. public void Reset (int count)
  130. {
  131. evt.Reset ();
  132. initialCount = initial = count;
  133. }
  134. public int CurrentCount {
  135. get {
  136. return initialCount;
  137. }
  138. }
  139. public int InitialCount {
  140. get {
  141. return initial;
  142. }
  143. }
  144. public bool IsSet {
  145. get {
  146. return initialCount == 0;
  147. }
  148. }
  149. public WaitHandle WaitHandle {
  150. get {
  151. return evt.WaitHandle;
  152. }
  153. }
  154. #region IDisposable implementation
  155. public void Dispose ()
  156. {
  157. }
  158. protected virtual void Dispose (bool disposing)
  159. {
  160. }
  161. #endregion
  162. }
  163. }
  164. #endif