public void OnFileChanged(TrackedFileEventArgs file) { if (CancellationToken.IsCancellationRequested) { return; } var filePath = file.Path; ICancellableTask task = null; // Check if we have an outstanding line count task. If we don't, kick one off lock (OutstandingLineCounts) { if (!OutstandingLineCounts.ContainsKey(filePath)) { // kick off and add line count task task = CancellableTaskRunner.Run(async token => { await CalculateLineCount(filePath, token); }, onThreadPoolThread: true); OutstandingLineCounts.Add(filePath, task); } } task?.Task.ContinueWith(t => { if (t.IsFaulted) { OnLineCountFailed?.Invoke(new LineCountFailedEventArgs(filePath, t.Exception)); } }); }
public void CancelTask(ICancellableTask cancelledTask) { var task = _scheduledTasks.SingleOrDefault(t => t.TaskId == cancelledTask.Id); if (task == null) { throw new NullReferenceException($"TaskId {cancelledTask.Id} could not be found"); } task.Cancel(); }
/// <summary> /// Waits for all of the passed in tasks to complete successfully or for any to fault or be canceled. /// If any fault or are canceled, all the tasks are canceled. /// If all complete successfully, the returned task is successful. /// If any task faults, the returned task's Exception property is an AggregateException that /// contains exceptions from all the tasks that faulted. If waitForCancellations is false, it will only contain exceptions /// from the first faulting task. /// If waitForCancellations is true and no task faulted but at least one was canceled, the returned task /// will be in the canceled state with the CancellationToken associated with the task. /// If waitForCancellations is false, with the first task canceled the returned task will be in the canceled /// state with the CancellationToken associated with the task. /// </summary> /// <param name="tasks"></param> /// <param name="waitForCancellations">If true, wait for all tasks to complete one way or another, /// whether successfully, faulted, or canceled, before the returned task becomes successful, faulted, or canceled. /// If false, then after any fault or cancellation, all tasks are cancelled and the returned task immediately /// becomes faulted or canceled without waiting for the other tasks to go into their cancelled state or fault.</param> public static Task WhenAllCancelOnFirstException(IEnumerable <ICancellableTask> tasks, bool waitForCancellations = true) { TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(); List <ICancellableTask> tasksList = tasks.ToList(); if (tasksList.Count == 0) { tcs.SetResult(null); return(tcs.Task); } object continuationLock = new object(); int tasksCompleteInAnyManner = 0; ICancellableTask firstTaskCanceled = null; List <Exception> exceptions = new List <Exception>(); bool cancellationsIssued = false; bool waitTaskCompleted = false; foreach (ICancellableTask cancellableTask in tasks) { cancellableTask.Task.ContinueWith(task => { lock (continuationLock) { // Don't bother doing the bookkeeping if we've already signaled the task. if (waitTaskCompleted) { return; } tasksCompleteInAnyManner++; if (task.IsFaulted) { exceptions.AddRange(task.Exception.InnerExceptions); } if (task.IsCanceled && firstTaskCanceled == null) { for (int i = 0; i < tasksList.Count; i++) { if (tasksList[i].Task == task) { firstTaskCanceled = tasksList[i]; } } } if (tasksCompleteInAnyManner == tasksList.Count) { // If all tasks finished but some faulted, set the exceptions for the wait task if (exceptions.Count > 0) { tcs.SetException(exceptions); waitTaskCompleted = true; } // If all tasks finished, none faulted, but at least one was canceled, set wait task as canceled else if (firstTaskCanceled != null) { tcs.TrySetCanceled(firstTaskCanceled.CancellationTokenSource.Token); waitTaskCompleted = true; } // If everything succeeded, signal the wait task as successful else { tcs.SetResult(null); waitTaskCompleted = true; } } else if (!waitForCancellations) { // If a task faulted and we're not waiting for all the tasks to finish their cancellation, // set the exceptions for the wait task. if (task.IsFaulted) { tcs.SetException(exceptions); waitTaskCompleted = true; } // If a task canceled and we're not waiting for all the tasks to finish their cancellation, // set the wait task as canceled else if (task.IsCanceled) { tcs.TrySetCanceled(firstTaskCanceled.CancellationTokenSource.Token); waitTaskCompleted = true; } } // Cancel all tasks if any task faults or is canceled. // Do this last because the continuation for the tasks we're cancelling can run // synchronously if the task has not been started yet and is associated with a // cancellation token. if ((task.IsCanceled || task.IsFaulted) && !cancellationsIssued) { cancellationsIssued = true; foreach (ICancellableTask taskToCancel in tasks) { taskToCancel.Cancel(); } } } }, TaskContinuationOptions.ExecuteSynchronously); } return(tcs.Task); }
public static void Cancel(this ICancellableTask cancellableTask) { cancellableTask.CancellationTokenSource.Cancel(); }