当您需要一组任务并行地运行一连串的阶段,但是每一个阶段都要等待所有其他任务都完成前一阶段之后才能开始,你一通过Barrier实例来同步这一类协同工作。Barrier初始化后,将等待特定数量的信号到来,这个数量在Barrier初始化时指定,在所指定的信号个数已经到来后,Barrier将执行一个指定的动作,这个动作也是在Barrier初始化时指定。Barrier在执行动作过后,将会重置,这时又将等待特定数量的信号到来,再执行指定动作。信号通过成员函数SignalAndWait()来发送,执行SignalAndWait()函数的Task或者线程将会投入等待,Barrier将等待特定数量的信号到达,然后Barrier执行完指定动作后被重置,这时SignalAndWait()函数所在的Task或者线程将继续运行。在程序的运行过程中,可以通过成员函数AddParticipant()和RemoveParticpant()来增加或者减少需要等待的信号数量。让我们来看看Barrier实现:
public class Barrier : IDisposable { // The first 15 bits are for the total count which means the maximum participants for the barrier is about 32K // The 16th bit is dummy // The next 15th bit for the current // And the last highest bit is for the sense volatile int m_currentTotalCount; const int CURRENT_MASK = 0x7FFF0000; const int TOTAL_MASK = 0x00007FFF; // Bitmask to extratc the sense flag const int SENSE_MASK = unchecked((int)0x80000000); // The maximum participants the barrier can operate = 32767 ( 2 power 15 - 1 ) const int MAX_PARTICIPANTS = TOTAL_MASK; long m_currentPhase; ManualResetEventSlim m_oddEvent; ManualResetEventSlim m_evenEvent; ExecutionContext m_ownerThreadContext; [SecurityCritical] private static ContextCallback s_invokePostPhaseAction; Action<Barrier> m_postPhaseAction; int m_actionCallerID; public Barrier(int participantCount): this(participantCount, null) {} public Barrier(int participantCount, Action<Barrier> postPhaseAction) { if (participantCount < 0 || participantCount > MAX_PARTICIPANTS) { throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString(SR.Barrier_ctor_ArgumentOutOfRange)); } m_currentTotalCount = (int)participantCount; m_postPhaseAction = postPhaseAction; m_oddEvent = new ManualResetEventSlim(true); m_evenEvent = new ManualResetEventSlim(false); // Capture the context if the post phase action is not null if (postPhaseAction != null && !ExecutionContext.IsFlowSuppressed()) { m_ownerThreadContext = ExecutionContext.Capture(); } m_actionCallerID = 0; } //<returns>The phase number of the barrier in which the new participants will first participate. public long AddParticipant() { try { return AddParticipants(1); } catch (ArgumentOutOfRangeException) { throw new InvalidOperationException(SR.GetString(SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange)); } } public long AddParticipants(int participantCount) { ThrowIfDisposed(); if (participantCount < 1 ) { throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString(SR.Barrier_AddParticipants_NonPositive_ArgumentOutOfRange)); } else if (participantCount > MAX_PARTICIPANTS) //overflow { throw new ArgumentOutOfRangeException("participantCount", SR.GetString(SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange)); } if (m_actionCallerI