3 // Copyright (c) 2008 Jérémie "Garuma" Laval
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:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
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
29 namespace System.Threading
31 [System.Diagnostics.DebuggerDisplayAttribute ("Initial Count={InitialCount}, Current Count={CurrentCount}")]
32 public class CountdownEvent : IDisposable
36 ManualResetEventSlim evt = new ManualResetEventSlim (false);
38 public CountdownEvent (int initialCount)
41 throw new ArgumentOutOfRangeException ("initialCount is negative");
42 this.initial = this.initialCount = initialCount;
50 public bool Signal (int signalCount)
53 throw new ArgumentOutOfRangeException ("signalCount");
55 Action<int> check = delegate (int value) {
57 throw new InvalidOperationException ("the specified initialCount is larger that CurrentCount");
61 if (!ApplyOperation (-signalCount, check, out newValue))
62 throw new InvalidOperationException ("The event is already set");
72 public void AddCount ()
77 public void AddCount (int signalCount)
80 throw new ArgumentOutOfRangeException ("signalCount");
82 if (!TryAddCount (signalCount))
83 throw new InvalidOperationException ("The event is already set");
86 public bool TryAddCount ()
88 return TryAddCount (1);
91 public bool TryAddCount (int signalCount)
94 throw new ArgumentOutOfRangeException ("signalCount");
96 return ApplyOperation (signalCount, null);
99 bool ApplyOperation (int num, Action<int> doCheck)
102 return ApplyOperation (num, doCheck, out temp);
105 bool ApplyOperation (int num, Action<int> doCheck, out int newValue)
111 oldCount = initialCount;
115 newValue = oldCount + num;
119 } while (Interlocked.CompareExchange (ref initialCount, newValue, oldCount) != oldCount);
129 public void Wait (CancellationToken cancellationToken)
131 evt.Wait (cancellationToken);
134 public bool Wait (int millisecondsTimeout)
136 return evt.Wait (millisecondsTimeout);
139 public bool Wait(TimeSpan timeout)
141 return evt.Wait (timeout);
144 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
146 return evt.Wait (millisecondsTimeout, cancellationToken);
149 public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
151 return evt.Wait (timeout, cancellationToken);
159 public void Reset (int count)
162 initialCount = initial = count;
165 public int CurrentCount {
171 public int InitialCount {
179 return initialCount == 0;
183 public WaitHandle WaitHandle {
185 return evt.WaitHandle;
189 #region IDisposable implementation
191 public void Dispose ()
196 protected virtual void Dispose (bool disposing)