5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
7 // Copyright (c) 2009 Jérémie "Garuma" Laval
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 using System.Diagnostics;
32 namespace System.Threading
34 [DebuggerDisplay ("Participant Count={ParticipantCount},Participants Remaining={ParticipantsRemaining}")]
35 public class Barrier : IDisposable
37 const int MaxParticipants = 32767;
38 Action<Barrier> postPhaseAction;
43 ManualResetEventSlim postPhaseEvt = new ManualResetEventSlim ();
46 public Barrier (int participantCount)
47 : this (participantCount, null)
51 public Barrier (int participantCount, Action<Barrier> postPhaseAction)
53 if (participantCount < 0 || participantCount > MaxParticipants)
54 throw new ArgumentOutOfRangeException ("participantCount");
56 this.participants = participantCount;
57 this.postPhaseAction = postPhaseAction;
59 InitCountdownEvent ();
62 public void Dispose ()
67 protected virtual void Dispose (bool disposing)
74 postPhaseAction = null;
79 void InitCountdownEvent ()
81 postPhaseEvt = new ManualResetEventSlim (false);
82 cntd = new CountdownEvent (participants);
85 public long AddParticipant ()
87 return AddParticipants (1);
90 static Exception GetDisposed ()
92 return new ObjectDisposedException ("Barrier");
95 public long AddParticipants (int participantCount)
100 if (participantCount < 0)
101 throw new InvalidOperationException ();
103 // Basically, we try to add ourselves and return
104 // the phase. If the call return false, we repeatdly try
105 // to add ourselves for the next phase
107 if (cntd.TryAddCount (participantCount)) {
108 Interlocked.Add (ref participants, participantCount);
114 public void RemoveParticipant ()
116 RemoveParticipants (1);
119 public void RemoveParticipants (int participantCount)
122 throw GetDisposed ();
123 if (participantCount < 0)
124 throw new ArgumentOutOfRangeException ("participantCount");
126 if (cntd.Signal (participantCount))
127 PostPhaseAction (postPhaseEvt);
129 Interlocked.Add (ref participants, -participantCount);
132 public void SignalAndWait ()
135 throw GetDisposed ();
136 SignalAndWait ((c) => { c.Wait (); return true; });
139 public void SignalAndWait (CancellationToken cancellationToken)
142 throw GetDisposed ();
143 SignalAndWait ((c) => { c.Wait (cancellationToken); return true; });
146 public bool SignalAndWait (int millisecondsTimeout)
149 throw GetDisposed ();
150 return SignalAndWait ((c) => c.Wait (millisecondsTimeout));
153 public bool SignalAndWait (TimeSpan timeout)
156 throw GetDisposed ();
157 return SignalAndWait ((c) => c.Wait (timeout));
160 public bool SignalAndWait (int millisecondsTimeout, CancellationToken cancellationToken)
163 throw GetDisposed ();
164 return SignalAndWait ((c) => c.Wait (millisecondsTimeout, cancellationToken));
167 public bool SignalAndWait (TimeSpan timeout, CancellationToken cancellationToken)
170 throw GetDisposed ();
171 return SignalAndWait ((c) => c.Wait (timeout, cancellationToken));
174 bool SignalAndWait (Func<CountdownEvent, bool> associate)
177 CountdownEvent temp = cntd;
178 ManualResetEventSlim evt = postPhaseEvt;
180 if (!temp.Signal ()) {
181 result = Wait (associate, temp, evt);
184 PostPhaseAction (evt);
190 bool Wait (Func<CountdownEvent, bool> associate, CountdownEvent temp, ManualResetEventSlim evt)
192 if (!associate (temp))
200 void PostPhaseAction (ManualResetEventSlim evt)
202 if (postPhaseAction != null) {
204 postPhaseAction (this);
205 } catch (Exception e) {
206 throw new BarrierPostPhaseException (e);
210 InitCountdownEvent ();
216 public long CurrentPhaseNumber {
222 public int ParticipantCount {
229 public int ParticipantsRemaining {