System.Threading.Barrier.SignalAndWait C# (CSharp) Method

SignalAndWait() public method

Signals that a participant has reached the barrier and waits for all other participants to reach the barrier as well, using a 32-bit signed integer to measure the time interval, while observing a .
is a /// negative number other than -1, which represents an infinite time-out. /// The method was invoked from within a post-phase action, the barrier currently has 0 participants, /// or the barrier is being used by more threads than are registered as participants. /// has been /// canceled. The current instance has already been /// disposed.
public SignalAndWait ( int millisecondsTimeout, CancellationToken cancellationToken ) : bool
millisecondsTimeout int The number of milliseconds to wait, or (-1) to wait indefinitely.
cancellationToken CancellationToken The to /// observe.
return bool
        public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested();

            if (millisecondsTimeout < -1)
            {
                throw new System.ArgumentOutOfRangeException(nameof(millisecondsTimeout), millisecondsTimeout,
                    SR.Barrier_SignalAndWait_ArgumentOutOfRange);
            }

            // in case of this is called from the PHA
            if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
            {
                throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
            }

            // local variables to extract the basic barrier variable and update them
            // The are declared here instead of inside the loop body because the will be used outside the loop
            bool sense; // The sense of the barrier *before* the phase associated with this SignalAndWait call completes
            int total;
            int current;
            int currentTotal;
            long phase;
            SpinWait spinner = new SpinWait();
            while (true)
            {
                currentTotal = _currentTotalCount;
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                phase = CurrentPhaseNumber;
                // throw if zero participants
                if (total == 0)
                {
                    throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ZeroTotal);
                }
                // Try to detect if the number of threads for this phase exceeded the total number of participants or not
                // This can be detected if the current is zero which means all participants for that phase has arrived and the phase number is not changed yet
                if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
                {
                    throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ThreadsExceeded);
                }
                //This is the last thread, finish the phase
                if (current + 1 == total)
                {
                    if (SetCurrentTotal(currentTotal, 0, total, !sense))
                    {
                        if (CdsSyncEtwBCLProvider.Log.IsEnabled())
                        {
                            CdsSyncEtwBCLProvider.Log.Barrier_PhaseFinished(sense, CurrentPhaseNumber);
                        }
                        FinishPhase(sense);
                        return true;
                    }
                }
                else if (SetCurrentTotal(currentTotal, current + 1, total, sense))
                {
                    break;
                }

                spinner.SpinOnce();
            }

            // ** Perform the real wait **
            // select the correct event to wait on, based on the current sense.
            ManualResetEventSlim eventToWaitOn = (sense) ? _evenEvent : _oddEvent;

            bool waitWasCanceled = false;
            bool waitResult = false;
            try
            {
                waitResult = DiscontinuousWait(eventToWaitOn, millisecondsTimeout, cancellationToken, phase);
            }
            catch (OperationCanceledException)
            {
                waitWasCanceled = true;
            }
            catch (ObjectDisposedException)// in case a race happen where one of the thread returned from SignalAndWait and the current thread calls Wait on a disposed event
            {
                // make sure the current phase for this thread is already finished, otherwise propagate the exception
                if (phase < CurrentPhaseNumber)
                    waitResult = true;
                else
                    throw;
            }

            if (!waitResult)
            {
                //reset the spinLock to prepare it for the next loop
                spinner.Reset();

                //If the wait timeout expired and all other thread didn't reach the barrier yet, update the current count back
                while (true)
                {
                    bool newSense;
                    currentTotal = _currentTotalCount;
                    GetCurrentTotal(currentTotal, out current, out total, out newSense);
                    // If the timeout expired and the phase has just finished, return true and this is considered as succeeded SignalAndWait
                    //otherwise the timeout expired and the current phase has not been finished yet, return false
                    //The phase is finished if the phase member variable is changed (incremented) or the sense has been changed
                    // we have to use the statements in the comparison below for two cases:
                    // 1- The sense is changed but the last thread didn't update the phase yet
                    // 2- The phase is already incremented but the sense flipped twice due to the termination of the next phase
                    if (phase < CurrentPhaseNumber || sense != newSense)
                    {
                        // The current phase has been finished, but we shouldn't return before the events are set/reset otherwise this thread could start
                        // next phase and the appropriate event has not reset yet which could make it return immediately from the next phase SignalAndWait
                        // before waiting other threads
                        WaitCurrentPhase(eventToWaitOn, phase);
                        Debug.Assert(phase < CurrentPhaseNumber);
                        break;
                    }
                    //The phase has not been finished yet, try to update the current count.
                    if (SetCurrentTotal(currentTotal, current - 1, total, sense))
                    {
                        //if here, then the attempt to backout was successful.
                        //throw (a fresh) oce if cancellation woke the wait
                        //or return false if it was the timeout that woke the wait.
                        //
                        if (waitWasCanceled)
                            throw new OperationCanceledException(SR.Common_OperationCanceled, cancellationToken);
                        else
                            return false;
                    }
                    spinner.SpinOnce();
                }
            }

            if (_exception != null)
                throw new BarrierPostPhaseException(_exception);

            return true;
        }

Same methods

Barrier::SignalAndWait ( TimeSpan timeout ) : Boolean
Barrier::SignalAndWait ( TimeSpan timeout, CancellationToken cancellationToken ) : Boolean
Barrier::SignalAndWait ( int millisecondsTimeout ) : bool
Barrier::SignalAndWait ( ) : void
Barrier::SignalAndWait ( CancellationToken cancellationToken ) : void

Usage Example

Beispiel #1
1
        /// <summary>
        /// Download all the images for the current session
        /// </summary>
        public void DownloadAllTreatmentImages()
        {
            Barrier barrier = new Barrier(_patient.PatientTreatment.TrainingList.Count + 2);

            Task treatmentThread = new Task(() =>
            {
                //Downloading all thumbs in treatment
                DownloadTreatment();

                barrier.SignalAndWait();
            });
            treatmentThread.Start();

            foreach(Training t in _patient.PatientTreatment.TrainingList)
            {
                Task tt = new Task(() =>
                {
                    DownloadTraining(_patient.PatientTreatment.TrainingList.IndexOf(t));
                    barrier.SignalAndWait();
                });
                tt.Start();

            }

            barrier.SignalAndWait();
            barrier.Dispose();
        }
All Usage Examples Of System.Threading.Barrier::SignalAndWait