2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System / System.Threading / Barrier.cs
blob401f7264dc3c3b8a05f135dda991b4929b973d42
1 #if NET_4_0
2 //
3 // Barrier.cs
4 //
5 // Author:
6 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
7 //
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
9 //
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:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
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
26 // THE SOFTWARE.
28 using System;
30 namespace System.Threading
32 public class Barrier : IDisposable
34 const int MAX_PARTICIPANTS = 32767;
35 Action<Barrier> postPhaseAction;
37 int participants;
38 CountdownEvent cntd;
39 AtomicBoolean cleaned = new AtomicBoolean ();
40 long phase;
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 ()
59 Dispose (true);
62 protected virtual void Dispose (bool disposing)
64 if (disposing){
65 if (cntd != null){
66 cntd.Dispose ();
67 cntd = null;
69 cleaned = null;
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)
92 if (cleaned == null)
93 throw GetDisposed ();
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
101 do {
102 if (cntd.TryAddCount (participantCount)) {
103 Interlocked.Add (ref participants, participantCount);
104 return phase;
106 } while (true);
109 public void RemoveParticipant ()
111 RemoveParticipants (1);
114 public void RemoveParticipants (int participantCount)
116 if (cleaned == null)
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 ()
128 if (cleaned == null)
129 throw GetDisposed ();
130 SignalAndWait ((c) => { c.Wait (); return true; });
133 public bool SignalAndWait (int millisecondTimeout)
135 if (cleaned == null)
136 throw GetDisposed ();
137 return SignalAndWait ((c) => c.Wait (millisecondTimeout));
140 public bool SignalAndWait (TimeSpan ts)
142 if (cleaned == null)
143 throw GetDisposed ();
144 return SignalAndWait ((c) => c.Wait (ts));
147 public bool SignalAndWait (int millisecondTimeout, CancellationToken token)
149 if (cleaned == null)
150 throw GetDisposed ();
151 return SignalAndWait ((c) => c.Wait (millisecondTimeout, token));
154 public bool SignalAndWait (TimeSpan ts, CancellationToken token)
156 if (cleaned == null)
157 throw GetDisposed ();
158 return SignalAndWait ((c) => c.Wait (ts, token));
161 bool SignalAndWait (Func<CountdownEvent, bool> associate)
163 bool result;
164 AtomicBoolean cl = cleaned;
165 CountdownEvent temp = cntd;
167 if (!temp.Signal ()) {
168 result = Wait (associate, temp, cl);
169 } else {
170 result = true;
171 PostPhaseAction (cl);
174 return result;
177 bool Wait (Func<CountdownEvent, bool> associate, CountdownEvent temp, AtomicBoolean cl)
179 if (!associate (temp))
180 return false;
182 SpinWait sw = new SpinWait ();
183 while (!cl.Value)
184 sw.SpinOnce ();
186 return true;
189 void PostPhaseAction (AtomicBoolean cl)
191 if (postPhaseAction != null)
192 postPhaseAction (this);
194 InitCountdownEvent ();
196 cl.Value = true;
197 phase++;
200 public long CurrentPhaseNumber {
201 get {
202 return phase;
206 public int ParticipantCount {
207 get {
208 return participants;
213 #endif