mscorlib(4.0.0.0) API with additions
Barrier.cs
1 using System.Diagnostics;
3 using System.Security;
5 
6 namespace System.Threading
7 {
9  [ComVisible(false)]
10  [DebuggerDisplay("Participant Count={ParticipantCount},Participants Remaining={ParticipantsRemaining}")]
11  [global::__DynamicallyInvokable]
12  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
13  public class Barrier : IDisposable
14  {
15  private volatile int m_currentTotalCount;
16 
17  private const int CURRENT_MASK = 2147418112;
18 
19  private const int TOTAL_MASK = 32767;
20 
21  private const int SENSE_MASK = int.MinValue;
22 
23  private const int MAX_PARTICIPANTS = 32767;
24 
25  private long m_currentPhase;
26 
27  private bool m_disposed;
28 
29  private ManualResetEventSlim m_oddEvent;
30 
31  private ManualResetEventSlim m_evenEvent;
32 
33  private ExecutionContext m_ownerThreadContext;
34 
35  [SecurityCritical]
36  private static ContextCallback s_invokePostPhaseAction;
37 
38  private Action<Barrier> m_postPhaseAction;
39 
40  private Exception m_exception;
41 
42  private int m_actionCallerID;
43 
46  [global::__DynamicallyInvokable]
47  public int ParticipantsRemaining
48  {
49  [global::__DynamicallyInvokable]
50  get
51  {
52  int currentTotalCount = m_currentTotalCount;
53  int num = currentTotalCount & 0x7FFF;
54  int num2 = (currentTotalCount & 0x7FFF0000) >> 16;
55  return num - num2;
56  }
57  }
58 
61  [global::__DynamicallyInvokable]
62  public int ParticipantCount
63  {
64  [global::__DynamicallyInvokable]
65  get
66  {
67  return m_currentTotalCount & 0x7FFF;
68  }
69  }
70 
73  [global::__DynamicallyInvokable]
74  public long CurrentPhaseNumber
75  {
76  [global::__DynamicallyInvokable]
77  get
78  {
79  return Volatile.Read(ref m_currentPhase);
80  }
81  internal set
82  {
83  Volatile.Write(ref m_currentPhase, value);
84  }
85  }
86 
91  [global::__DynamicallyInvokable]
92  public Barrier(int participantCount)
93  : this(participantCount, null)
94  {
95  }
96 
102  [global::__DynamicallyInvokable]
103  public Barrier(int participantCount, Action<Barrier> postPhaseAction)
104  {
105  if (participantCount < 0 || participantCount > 32767)
106  {
107  throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString("Barrier_ctor_ArgumentOutOfRange"));
108  }
109  m_currentTotalCount = participantCount;
110  m_postPhaseAction = postPhaseAction;
111  m_oddEvent = new ManualResetEventSlim(initialState: true);
112  m_evenEvent = new ManualResetEventSlim(initialState: false);
113  if (postPhaseAction != null && !ExecutionContext.IsFlowSuppressed())
114  {
115  m_ownerThreadContext = ExecutionContext.Capture();
116  }
117  m_actionCallerID = 0;
118  }
119 
120  private void GetCurrentTotal(int currentTotal, out int current, out int total, out bool sense)
121  {
122  total = (currentTotal & 0x7FFF);
123  current = (currentTotal & 0x7FFF0000) >> 16;
124  sense = (((currentTotal & int.MinValue) == 0) ? true : false);
125  }
126 
127  private bool SetCurrentTotal(int currentTotal, int current, int total, bool sense)
128  {
129  int num = (current << 16) | total;
130  if (!sense)
131  {
132  num |= int.MinValue;
133  }
134  return Interlocked.CompareExchange(ref m_currentTotalCount, num, currentTotal) == currentTotal;
135  }
136 
141  [global::__DynamicallyInvokable]
142  public long AddParticipant()
143  {
144  try
145  {
146  return AddParticipants(1);
147  }
149  {
150  throw new InvalidOperationException(SR.GetString("Barrier_AddParticipants_Overflow_ArgumentOutOfRange"));
151  }
152  }
153 
161  [global::__DynamicallyInvokable]
162  public long AddParticipants(int participantCount)
163  {
164  ThrowIfDisposed();
165  if (participantCount < 1)
166  {
167  throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString("Barrier_AddParticipants_NonPositive_ArgumentOutOfRange"));
168  }
169  if (participantCount > 32767)
170  {
171  throw new ArgumentOutOfRangeException("participantCount", SR.GetString("Barrier_AddParticipants_Overflow_ArgumentOutOfRange"));
172  }
173  if (m_actionCallerID != 0 && Thread.CurrentThread.ManagedThreadId == m_actionCallerID)
174  {
175  throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
176  }
177  SpinWait spinWait = default(SpinWait);
178  long num = 0L;
179  bool sense;
180  while (true)
181  {
182  int currentTotalCount = m_currentTotalCount;
183  GetCurrentTotal(currentTotalCount, out int current, out int total, out sense);
184  if (participantCount + total > 32767)
185  {
186  throw new ArgumentOutOfRangeException("participantCount", SR.GetString("Barrier_AddParticipants_Overflow_ArgumentOutOfRange"));
187  }
188  if (SetCurrentTotal(currentTotalCount, current, total + participantCount, sense))
189  {
190  break;
191  }
192  spinWait.SpinOnce();
193  }
194  long currentPhaseNumber = CurrentPhaseNumber;
195  num = ((sense != (currentPhaseNumber % 2 == 0)) ? (currentPhaseNumber + 1) : currentPhaseNumber);
196  if (num != currentPhaseNumber)
197  {
198  if (sense)
199  {
200  m_oddEvent.Wait();
201  }
202  else
203  {
204  m_evenEvent.Wait();
205  }
206  }
207  else if (sense && m_evenEvent.IsSet)
208  {
209  m_evenEvent.Reset();
210  }
211  else if (!sense && m_oddEvent.IsSet)
212  {
213  m_oddEvent.Reset();
214  }
215  return num;
216  }
217 
221  [global::__DynamicallyInvokable]
222  public void RemoveParticipant()
223  {
225  }
226 
234  [global::__DynamicallyInvokable]
235  public void RemoveParticipants(int participantCount)
236  {
237  ThrowIfDisposed();
238  if (participantCount < 1)
239  {
240  throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString("Barrier_RemoveParticipants_NonPositive_ArgumentOutOfRange"));
241  }
242  if (m_actionCallerID != 0 && Thread.CurrentThread.ManagedThreadId == m_actionCallerID)
243  {
244  throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
245  }
246  SpinWait spinWait = default(SpinWait);
247  bool sense;
248  while (true)
249  {
250  int currentTotalCount = m_currentTotalCount;
251  GetCurrentTotal(currentTotalCount, out int current, out int total, out sense);
252  if (total < participantCount)
253  {
254  throw new ArgumentOutOfRangeException("participantCount", SR.GetString("Barrier_RemoveParticipants_ArgumentOutOfRange"));
255  }
256  if (total - participantCount < current)
257  {
258  throw new InvalidOperationException(SR.GetString("Barrier_RemoveParticipants_InvalidOperation"));
259  }
260  int num = total - participantCount;
261  if (num > 0 && current == num)
262  {
263  if (SetCurrentTotal(currentTotalCount, 0, total - participantCount, !sense))
264  {
265  break;
266  }
267  }
268  else if (SetCurrentTotal(currentTotalCount, current, total - participantCount, sense))
269  {
270  return;
271  }
272  spinWait.SpinOnce();
273  }
274  FinishPhase(sense);
275  }
276 
281  [global::__DynamicallyInvokable]
282  public void SignalAndWait()
283  {
285  }
286 
293  [global::__DynamicallyInvokable]
294  public void SignalAndWait(CancellationToken cancellationToken)
295  {
296  SignalAndWait(-1, cancellationToken);
297  }
298 
306  [global::__DynamicallyInvokable]
307  public bool SignalAndWait(TimeSpan timeout)
308  {
309  return SignalAndWait(timeout, default(CancellationToken));
310  }
311 
322  [global::__DynamicallyInvokable]
323  public bool SignalAndWait(TimeSpan timeout, CancellationToken cancellationToken)
324  {
325  long num = (long)timeout.TotalMilliseconds;
326  if (num < -1 || num > int.MaxValue)
327  {
328  throw new ArgumentOutOfRangeException("timeout", timeout, SR.GetString("Barrier_SignalAndWait_ArgumentOutOfRange"));
329  }
330  return SignalAndWait((int)timeout.TotalMilliseconds, cancellationToken);
331  }
332 
341  [global::__DynamicallyInvokable]
342  public bool SignalAndWait(int millisecondsTimeout)
343  {
344  return SignalAndWait(millisecondsTimeout, default(CancellationToken));
345  }
346 
357  [global::__DynamicallyInvokable]
358  public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
359  {
360  ThrowIfDisposed();
361  cancellationToken.ThrowIfCancellationRequested();
362  if (millisecondsTimeout < -1)
363  {
364  throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, SR.GetString("Barrier_SignalAndWait_ArgumentOutOfRange"));
365  }
366  if (m_actionCallerID != 0 && Thread.CurrentThread.ManagedThreadId == m_actionCallerID)
367  {
368  throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
369  }
370  SpinWait spinWait = default(SpinWait);
371  int current;
372  int total;
373  bool sense;
374  long currentPhaseNumber;
375  while (true)
376  {
377  int currentTotalCount = m_currentTotalCount;
378  GetCurrentTotal(currentTotalCount, out current, out total, out sense);
379  currentPhaseNumber = CurrentPhaseNumber;
380  if (total == 0)
381  {
382  throw new InvalidOperationException(SR.GetString("Barrier_SignalAndWait_InvalidOperation_ZeroTotal"));
383  }
384  if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
385  {
386  throw new InvalidOperationException(SR.GetString("Barrier_SignalAndWait_InvalidOperation_ThreadsExceeded"));
387  }
388  if (current + 1 == total)
389  {
390  if (SetCurrentTotal(currentTotalCount, 0, total, !sense))
391  {
392  if (CdsSyncEtwBCLProvider.Log.IsEnabled())
393  {
394  CdsSyncEtwBCLProvider.Log.Barrier_PhaseFinished(sense, CurrentPhaseNumber);
395  }
396  FinishPhase(sense);
397  return true;
398  }
399  }
400  else if (SetCurrentTotal(currentTotalCount, current + 1, total, sense))
401  {
402  break;
403  }
404  spinWait.SpinOnce();
405  }
406  ManualResetEventSlim currentPhaseEvent = sense ? m_evenEvent : m_oddEvent;
407  bool flag = false;
408  bool flag2 = false;
409  try
410  {
411  flag2 = DiscontinuousWait(currentPhaseEvent, millisecondsTimeout, cancellationToken, currentPhaseNumber);
412  }
414  {
415  flag = true;
416  }
418  {
419  if (currentPhaseNumber >= CurrentPhaseNumber)
420  {
421  throw;
422  }
423  flag2 = true;
424  }
425  if (!flag2)
426  {
427  spinWait.Reset();
428  while (true)
429  {
430  int currentTotalCount = m_currentTotalCount;
431  GetCurrentTotal(currentTotalCount, out current, out total, out bool sense2);
432  if (currentPhaseNumber < CurrentPhaseNumber || sense != sense2)
433  {
434  break;
435  }
436  if (SetCurrentTotal(currentTotalCount, current - 1, total, sense))
437  {
438  if (flag)
439  {
440  throw new OperationCanceledException(SR.GetString("Common_OperationCanceled"), cancellationToken);
441  }
442  return false;
443  }
444  spinWait.SpinOnce();
445  }
446  WaitCurrentPhase(currentPhaseEvent, currentPhaseNumber);
447  }
448  if (m_exception != null)
449  {
450  throw new BarrierPostPhaseException(m_exception);
451  }
452  return true;
453  }
454 
455  [SecuritySafeCritical]
456  private void FinishPhase(bool observedSense)
457  {
458  if (m_postPhaseAction != null)
459  {
460  try
461  {
462  m_actionCallerID = Thread.CurrentThread.ManagedThreadId;
463  if (m_ownerThreadContext != null)
464  {
465  ExecutionContext ownerThreadContext = m_ownerThreadContext;
466  m_ownerThreadContext = m_ownerThreadContext.CreateCopy();
467  ContextCallback callback = InvokePostPhaseAction;
468  ExecutionContext.Run(ownerThreadContext, callback, this);
469  ownerThreadContext.Dispose();
470  }
471  else
472  {
473  m_postPhaseAction(this);
474  }
475  m_exception = null;
476  }
477  catch (Exception exception)
478  {
479  Exception ex = m_exception = exception;
480  }
481  finally
482  {
483  m_actionCallerID = 0;
484  SetResetEvents(observedSense);
485  if (m_exception != null)
486  {
487  throw new BarrierPostPhaseException(m_exception);
488  }
489  }
490  }
491  else
492  {
493  SetResetEvents(observedSense);
494  }
495  }
496 
497  [SecurityCritical]
498  private static void InvokePostPhaseAction(object obj)
499  {
500  Barrier barrier = (Barrier)obj;
501  barrier.m_postPhaseAction(barrier);
502  }
503 
504  private void SetResetEvents(bool observedSense)
505  {
507  if (observedSense)
508  {
509  m_oddEvent.Reset();
510  m_evenEvent.Set();
511  }
512  else
513  {
514  m_evenEvent.Reset();
515  m_oddEvent.Set();
516  }
517  }
518 
519  private void WaitCurrentPhase(ManualResetEventSlim currentPhaseEvent, long observedPhase)
520  {
521  SpinWait spinWait = default(SpinWait);
522  while (!currentPhaseEvent.IsSet && CurrentPhaseNumber - observedPhase <= 1)
523  {
524  spinWait.SpinOnce();
525  }
526  }
527 
528  private bool DiscontinuousWait(ManualResetEventSlim currentPhaseEvent, int totalTimeout, CancellationToken token, long observedPhase)
529  {
530  int num = 100;
531  int num2 = 10000;
532  while (observedPhase == CurrentPhaseNumber)
533  {
534  int num3 = (totalTimeout == -1) ? num : Math.Min(num, totalTimeout);
535  if (currentPhaseEvent.Wait(num3, token))
536  {
537  return true;
538  }
539  if (totalTimeout != -1)
540  {
541  totalTimeout -= num3;
542  if (totalTimeout <= 0)
543  {
544  return false;
545  }
546  }
547  num = ((num >= num2) ? num2 : Math.Min(num << 1, num2));
548  }
549  WaitCurrentPhase(currentPhaseEvent, observedPhase);
550  return true;
551  }
552 
555  [global::__DynamicallyInvokable]
556  public void Dispose()
557  {
558  if (m_actionCallerID != 0 && Thread.CurrentThread.ManagedThreadId == m_actionCallerID)
559  {
560  throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
561  }
562  Dispose(disposing: true);
563  GC.SuppressFinalize(this);
564  }
565 
568  [global::__DynamicallyInvokable]
569  protected virtual void Dispose(bool disposing)
570  {
571  if (m_disposed)
572  {
573  return;
574  }
575  if (disposing)
576  {
577  m_oddEvent.Dispose();
578  m_evenEvent.Dispose();
579  if (m_ownerThreadContext != null)
580  {
581  m_ownerThreadContext.Dispose();
582  m_ownerThreadContext = null;
583  }
584  }
585  m_disposed = true;
586  }
587 
588  private void ThrowIfDisposed()
589  {
590  if (m_disposed)
591  {
592  throw new ObjectDisposedException("Barrier", SR.GetString("Barrier_Dispose"));
593  }
594  }
595  }
596 }
static Thread CurrentThread
Gets the currently running thread.
Definition: Thread.cs:134
ExecutionContext CreateCopy()
Creates a copy of the current execution context.
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.ManualResetEventSlim cl...
static void Write(ref bool location, bool value)
Writes the specified value to the specified field. On systems that require it, inserts a memory barri...
Definition: Volatile.cs:186
Propagates notification that operations should be canceled.
delegate void ContextCallback(object state)
Represents a method to be called within a new context.
void ThrowIfCancellationRequested()
Throws a T:System.OperationCanceledException if this token has had cancellation requested.
void Reset()
Resets the spin counter.
Definition: SpinWait.cs:76
virtual void Dispose(bool disposing)
Releases the unmanaged resources used by the T:System.Threading.Barrier, and optionally releases the ...
Definition: Barrier.cs:569
long AddParticipant()
Notifies the T:System.Threading.Barrier that there will be an additional participant.
Definition: Barrier.cs:142
static void SuppressFinalize(object obj)
Requests that the common language runtime not call the finalizer for the specified object.
Definition: GC.cs:308
void SignalAndWait()
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:282
void SignalAndWait(CancellationToken cancellationToken)
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:294
Provides support for spin-based waiting.
Definition: SpinWait.cs:8
void RemoveParticipant()
Notifies the T:System.Threading.Barrier that there will be one less participant.
Definition: Barrier.cs:222
long AddParticipants(int participantCount)
Notifies the T:System.Threading.Barrier that there will be additional participants.
Definition: Barrier.cs:162
Provides a mechanism for releasing unmanaged resources.To browse the .NET Framework source code for t...
Definition: IDisposable.cs:8
Definition: __Canon.cs:3
The exception that is thrown when the value of an argument is outside the allowable range of values a...
double TotalMilliseconds
Gets the value of the current T:System.TimeSpan structure expressed in whole and fractional milliseco...
Definition: TimeSpan.cs:180
bool SignalAndWait(TimeSpan timeout, CancellationToken cancellationToken)
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:323
bool SignalAndWait(int millisecondsTimeout)
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:342
void Wait()
Blocks the current thread until the current T:System.Threading.ManualResetEventSlim is set.
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.Barrier class.
Definition: Barrier.cs:556
bool SignalAndWait(TimeSpan timeout)
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:307
int ParticipantCount
Gets the total number of participants in the barrier.
Definition: Barrier.cs:63
The exception that is thrown when an operation is performed on a disposed object.
SecurityAction
Specifies the security actions that can be performed using declarative security.
Manages the execution context for the current thread. This class cannot be inherited.
void Set()
Sets the state of the event to signaled, which allows one or more threads waiting on the event to pro...
void RemoveParticipants(int participantCount)
Notifies the T:System.Threading.Barrier that there will be fewer participants.
Definition: Barrier.cs:235
Provides a slimmed down version of T:System.Threading.ManualResetEvent.
Enables multiple tasks to cooperatively work on an algorithm in parallel through multiple phases.
Definition: Barrier.cs:13
Contains methods for performing volatile memory operations.
Definition: Volatile.cs:8
static void Run(ExecutionContext executionContext, ContextCallback callback, object state)
Runs a method in a specified execution context on the current thread.
bool? IsSet
Gets whether the event is set.
Barrier(int participantCount, Action< Barrier > postPhaseAction)
Initializes a new instance of the T:System.Threading.Barrier class.
Definition: Barrier.cs:103
static bool Read(ref bool location)
Reads the value of the specified field. On systems that require it, inserts a memory barrier that pre...
Definition: Volatile.cs:15
Controls the system garbage collector, a service that automatically reclaims unused memory.
Definition: GC.cs:11
bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
Signals that a participant has reached the barrier and waits for all other participants to reach the ...
Definition: Barrier.cs:358
static ExecutionContext Capture()
Captures the execution context from the current thread.
Barrier(int participantCount)
Initializes a new instance of the T:System.Threading.Barrier class.
Definition: Barrier.cs:92
static bool IsFlowSuppressed()
Indicates whether the flow of the execution context is currently suppressed.
The exception that is thrown in a thread upon cancellation of an operation that the thread was execut...
int ManagedThreadId
Gets a unique identifier for the current managed thread.
Definition: Thread.cs:55
Represents errors that occur during application execution.To browse the .NET Framework source code fo...
Definition: Exception.cs:22
void SpinOnce()
Performs a single spin.
Definition: SpinWait.cs:48
int ParticipantsRemaining
Gets the number of participants in the barrier that haven’t yet signaled in the current phase.
Definition: Barrier.cs:48
Represents a time interval.To browse the .NET Framework source code for this type,...
Definition: TimeSpan.cs:12
The exception that is thrown when the post-phase action of a T:System.Threading.Barrier fails
The exception that is thrown when a method call is invalid for the object's current state.
long CurrentPhaseNumber
Gets the number of the barrier's current phase.
Definition: Barrier.cs:75
void Reset()
Sets the state of the event to nonsignaled, which causes threads to block.
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.ExecutionContext class.
Creates and controls a thread, sets its priority, and gets its status.
Definition: Thread.cs:18