Beispiel #1
0
        public void UnlockCompetition(CancellationToken cancellationToken)
        {
            CancellationTokenRegistration registration = cancellationToken
                                                         .Register
                                                         (
                state =>
            {
                ExclusiveCompletionSourceGroup <T> group = state as ExclusiveCompletionSourceGroup <T>;

                /// There are 2 cases here.
                ///
                /// #1: The token is canceled before <see cref="UnlockCompetition(CancellationToken)"/> is called, but after the token is validated higher up the stack.
                /// Is this is the case, the cancellation callbak will be called synchronously while <see cref="_completedSource"/> is still set to <see cref="State.Locked"/>.
                /// So the competition will never progress to <see cref="State.Unlocked"/> and we have to check for this explicitly.
                ///
                /// #2: We're canceled after the competition has been unlocked.
                /// If this is the case, we have a simple race against the awaiters to progress from <see cref="State.Unlocked"/> to <see cref="State.Canceled"/>.
                if (group.TryTransitionToCanceledIfStateIs(State.Locked) || group.TryTransitionToCanceledIfStateIs(State.Unlocked))
                {
                    group._realCompetionSource.SetCanceled();
                }
            },
                this,
                useSynchronizationContext: false
                                                         );

            // We can't do volatile reads/writes on a custom value type field, so we have to wrap the registration into a holder instance.
            // But there's no point in allocating the wrapper if the token can never be canceled.
            if (cancellationToken.CanBeCanceled)
            {
                Volatile.Write(ref _cancellationRegistrationHolder, new CancellationRegistrationHolder(registration));
            }

            // If the cancellation was processed synchronously, the state will already be set to Canceled and we must *NOT* unlock the competition.
            Interlocked.CompareExchange(ref _completedSource, State.Unlocked, State.Locked);
        }
Beispiel #2
0
 public Factory(ExclusiveCompletionSourceGroup <T> group, int index)
 {
     _group = group;
     _index = index;
 }
Beispiel #3
0
 public ExclusiveCompletionSource(ExclusiveCompletionSourceGroup <T> group, int id)
 {
     _group = group;
     _id    = id;
 }