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
27 #if NET_4_0 || BOOTSTRAP_NET_4_0
31 namespace System.Threading
33 public class Barrier : IDisposable
35 const int MaxParticipants = 32767;
36 Action<Barrier> postPhaseAction;
41 ManualResetEventSlim postPhaseEvt = new ManualResetEventSlim ();
44 public Barrier (int participants) : this (participants, null)
48 public Barrier (int participants, Action<Barrier> postPhaseAction)
50 if (participants < 0 || participants > MaxParticipants)
51 throw new ArgumentOutOfRangeException ("participants");
53 this.participants = participants;
54 this.postPhaseAction = postPhaseAction;
56 InitCountdownEvent ();
59 public void Dispose ()
64 protected virtual void Dispose (bool disposing)
71 postPhaseAction = null;
76 void InitCountdownEvent ()
78 postPhaseEvt = new ManualResetEventSlim (false);
79 cntd = new CountdownEvent (participants);
82 public long AddParticipant ()
84 return AddParticipants (1);
87 static Exception GetDisposed ()
89 return new ObjectDisposedException ("Barrier");
92 public long AddParticipants (int participantCount)
97 if (participantCount < 0)
98 throw new InvalidOperationException ();
100 // Basically, we try to add ourselves and return
101 // the phase. If the call return false, we repeatdly try
102 // to add ourselves for the next phase
104 if (cntd.TryAddCount (participantCount)) {
105 Interlocked.Add (ref participants, participantCount);
111 public void RemoveParticipant ()
113 RemoveParticipants (1);
116 public void RemoveParticipants (int participantCount)
119 throw GetDisposed ();
120 if (participantCount < 0)
121 throw new ArgumentOutOfRangeException ("participantCount");
123 if (cntd.Signal (participantCount))
124 PostPhaseAction (postPhaseEvt);
126 Interlocked.Add (ref participants, -participantCount);
129 public void SignalAndWait ()
132 throw GetDisposed ();
133 SignalAndWait ((c) => { c.Wait (); return true; });
136 public void SignalAndWait (CancellationToken token)
139 throw GetDisposed ();
140 SignalAndWait ((c) => { c.Wait (token); return true; });
143 public bool SignalAndWait (int millisecondTimeout)
146 throw GetDisposed ();
147 return SignalAndWait ((c) => c.Wait (millisecondTimeout));
150 public bool SignalAndWait (TimeSpan ts)
153 throw GetDisposed ();
154 return SignalAndWait ((c) => c.Wait (ts));
157 public bool SignalAndWait (int millisecondTimeout, CancellationToken token)
160 throw GetDisposed ();
161 return SignalAndWait ((c) => c.Wait (millisecondTimeout, token));
164 public bool SignalAndWait (TimeSpan ts, CancellationToken token)
167 throw GetDisposed ();
168 return SignalAndWait ((c) => c.Wait (ts, token));
171 bool SignalAndWait (Func<CountdownEvent, bool> associate)
174 CountdownEvent temp = cntd;
175 ManualResetEventSlim evt = postPhaseEvt;
177 if (!temp.Signal ()) {
178 result = Wait (associate, temp, evt);
181 PostPhaseAction (evt);
187 bool Wait (Func<CountdownEvent, bool> associate, CountdownEvent temp, ManualResetEventSlim evt)
189 if (!associate (temp))
197 void PostPhaseAction (ManualResetEventSlim evt)
199 if (postPhaseAction != null) {
201 postPhaseAction (this);
202 } catch (Exception e) {
203 throw new BarrierPostPhaseException (e);
207 InitCountdownEvent ();
213 public long CurrentPhaseNumber {
219 public int ParticipantCount {