6 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 namespace System
.Threading
32 public class Barrier
: IDisposable
34 const int MAX_PARTICIPANTS
= 32767;
35 Action
<Barrier
> postPhaseAction
;
39 AtomicBoolean cleaned
= new AtomicBoolean ();
42 public Barrier (int participants
) : this (participants
, null)
46 public Barrier (int participants
, Action
<Barrier
> postPhaseAction
)
48 if (participants
< 0 || participants
> MAX_PARTICIPANTS
)
49 throw new ArgumentOutOfRangeException ("participants");
51 this.participants
= participants
;
52 this.postPhaseAction
= postPhaseAction
;
54 InitCountdownEvent ();
57 public void Dispose ()
62 protected virtual void Dispose (bool disposing
)
70 postPhaseAction
= null;
74 void InitCountdownEvent ()
76 cleaned
= new AtomicBoolean ();
77 cntd
= new CountdownEvent (participants
);
80 public long AddParticipant ()
82 return AddParticipants (1);
85 static Exception
GetDisposed ()
87 return new ObjectDisposedException ("Barrier");
90 public long AddParticipants (int participantCount
)
95 if (participantCount
< 0)
96 throw new InvalidOperationException ();
98 // Basically, we try to add ourselves and return
99 // the phase. If the call return false, we repeatdly try
100 // to add ourselves for the next phase
102 if (cntd
.TryAddCount (participantCount
)) {
103 Interlocked
.Add (ref participants
, participantCount
);
109 public void RemoveParticipant ()
111 RemoveParticipants (1);
114 public void RemoveParticipants (int participantCount
)
117 throw GetDisposed ();
118 if (participantCount
< 0)
119 throw new ArgumentOutOfRangeException ("participantCount");
121 if (cntd
.Signal (participantCount
))
122 PostPhaseAction (cleaned
);
123 Interlocked
.Add (ref participants
, -participantCount
);
126 public void SignalAndWait ()
129 throw GetDisposed ();
130 SignalAndWait ((c
) => { c.Wait (); return true; }
);
133 public bool SignalAndWait (int millisecondTimeout
)
136 throw GetDisposed ();
137 return SignalAndWait ((c
) => c
.Wait (millisecondTimeout
));
140 public bool SignalAndWait (TimeSpan ts
)
143 throw GetDisposed ();
144 return SignalAndWait ((c
) => c
.Wait (ts
));
147 public bool SignalAndWait (int millisecondTimeout
, CancellationToken token
)
150 throw GetDisposed ();
151 return SignalAndWait ((c
) => c
.Wait (millisecondTimeout
, token
));
154 public bool SignalAndWait (TimeSpan ts
, CancellationToken token
)
157 throw GetDisposed ();
158 return SignalAndWait ((c
) => c
.Wait (ts
, token
));
161 bool SignalAndWait (Func
<CountdownEvent
, bool> associate
)
164 AtomicBoolean cl
= cleaned
;
165 CountdownEvent temp
= cntd
;
167 if (!temp
.Signal ()) {
168 result
= Wait (associate
, temp
, cl
);
171 PostPhaseAction (cl
);
177 bool Wait (Func
<CountdownEvent
, bool> associate
, CountdownEvent temp
, AtomicBoolean cl
)
179 if (!associate (temp
))
182 SpinWait sw
= new SpinWait ();
189 void PostPhaseAction (AtomicBoolean cl
)
191 if (postPhaseAction
!= null)
192 postPhaseAction (this);
194 InitCountdownEvent ();
200 public long CurrentPhaseNumber
{
206 public int ParticipantCount
{