Exemplo n.º 1
0
        /// <summary>
        /// Handles one waiting task can be cancelled.
        /// </summary>
        /// <param name="status">The status of the waiting task being cancelled.</param>
        private void OnWaitingTaskCancelled(WaitingCancellationStatus status)
        {
            CancellationTokenSource?overallCancellationSource = null;

            lock (this.syncObject)
            {
                if (--this.outstandingWaitingCount != 0 || !this.isCancellationAllowed)
                {
                    // when overall cancellation is not allowed, we cancel this single waiting task.
                    status.TrySetCanceled(status.CancellationToken);
                }
                else
                {
                    // otherwise, we cancel the overall computation, when it is done, it will cancel the current waiting task.
                    overallCancellationSource = this.combinedCancellationTokenSource;
                    if (overallCancellationSource is not null)
                    {
                        this.combinedCancellationTokenSource = null;
                        this.isCancellationRequested         = true;
                    }
                }
            }

            if (overallCancellationSource is not null)
            {
                overallCancellationSource.Cancel();
                overallCancellationSource.Dispose();
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CancellableJoinComputation"/> class.
        /// </summary>
        /// <param name="taskFactory">A callback to create the task.</param>
        /// <param name="allowCancelled">Whether the inner task can be cancelled.</param>
        internal CancellableJoinComputation(Func <CancellationToken, Task> taskFactory, bool allowCancelled)
        {
            Requires.NotNull(taskFactory, nameof(taskFactory));

            if (allowCancelled)
            {
                this.isCancellationAllowed           = true;
                this.combinedCancellationTokenSource = new CancellationTokenSource();
                this.joinedWaitingList = new List <WaitingCancellationStatus>(capacity: 2);
            }

            this.InnerTask = taskFactory(this.combinedCancellationTokenSource?.Token ?? CancellationToken.None);

            if (allowCancelled)
            {
                // Note: this continuation is chained asynchronously to prevent being inlined when we trigger the combined cancellation token.
                this.InnerTask.ContinueWith(
                    (t, s) =>
                {
                    var me = (CancellableJoinComputation)s !;

                    List <WaitingCancellationStatus> allWaitingTasks;
                    CancellationTokenSource?combinedCancellationTokenSource;
                    lock (me.syncObject)
                    {
                        Assumes.NotNull(me.joinedWaitingList);

                        allWaitingTasks = me.joinedWaitingList;
                        combinedCancellationTokenSource = me.combinedCancellationTokenSource;

                        me.joinedWaitingList = null;
                        me.combinedCancellationTokenSource = null;
                    }

                    combinedCancellationTokenSource?.Dispose();

                    if (t.IsCanceled)
                    {
                        for (int i = 0; i < allWaitingTasks.Count; i++)
                        {
                            WaitingCancellationStatus status = allWaitingTasks[i];
                            if (status.CancellationToken.IsCancellationRequested)
                            {
                                status.TrySetCanceled(status.CancellationToken);
                            }
                            else
                            {
                                status.TrySetCanceled();
                            }

                            status.Dispose();
                        }
                    }
                    else if (t.IsFaulted)
                    {
                        System.Collections.ObjectModel.ReadOnlyCollection <Exception> exceptions = t.Exception !.InnerExceptions;
                        for (int i = 0; i < allWaitingTasks.Count; i++)
                        {
                            WaitingCancellationStatus status = allWaitingTasks[i];
                            status.TrySetException(exceptions);
                            status.Dispose();
                        }
                    }
                    else
                    {
                        for (int i = 0; i < allWaitingTasks.Count; i++)
                        {
                            WaitingCancellationStatus status = allWaitingTasks[i];
                            status.TrySetResult(true);
                            status.Dispose();
                        }
                    }
                },
                    this,
                    CancellationToken.None,
                    TaskContinuationOptions.RunContinuationsAsynchronously,
                    TaskScheduler.Default).Forget();
            }
        }