/// <summary> /// Stops work gracefully. All backlog will be processed. /// </summary> public void Complete() { switch (State) { case States.Idle: _completionSource.TrySetResult(); break; case States.Processing: State = States.FinalProcessing; break; case States.FinalProcessing: case States.Aborted: break; default: throw new ArgumentOutOfRangeException(nameof(State), "Unexpected state."); } }
/// <summary> /// Attempts to transition the underlying task into the <see cref="SystemTasks.TaskStatus.RanToCompletion"/> state. /// </summary> public static bool TrySetResult(SystemTaskCompletionSource tcs) => tcs.TrySetResult();
/// <summary></summary> /// <typeparam name="TResult"></typeparam> /// <param name="tasks"></param> /// <returns></returns> public static Task <Task <TResult> > WhenAny <TResult>(IEnumerable <Task <TResult> > tasks) { if (tasks == null) { throw new ArgumentNullException("tasks"); } Contract.EndContractBlock(); var tcs = new TaskCompletionSource <Task <TResult> >(); Task.Factory.ContinueWhenAny((tasks as Task <TResult>[]) ?? tasks.ToArray(), (Task <TResult> completed) => tcs.TrySetResult(completed), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return(tcs.Task); }
/// <summary> /// Asynchronously iterates through an enumerable of tasks. /// </summary> /// <param name="factory">The target factory.</param> /// <param name="source">The enumerable containing the tasks to be iterated through.</param> /// <param name="state">The asynchronous state for the returned Task.</param> /// <param name="cancellationToken">The cancellation token used to cancel the iteration.</param> /// <param name="creationOptions">Options that control the task's behavior.</param> /// <param name="scheduler">The scheduler to which tasks will be scheduled.</param> /// <returns>A Task that represents the complete asynchronous operation.</returns> public static Task Iterate(this TaskFactory factory, IEnumerable <object> source, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { // Validate/update parameters Contract.Requires(factory != null); Contract.Requires(source != null); Contract.Requires(scheduler != null); // Get an enumerator from the enumerable var enumerator = source.GetEnumerator(); if (enumerator == null) { throw new InvalidOperationException("Invalid enumerable - GetEnumerator returned null"); } // Create the task to be returned to the caller. And ensure // that when everything is done, the enumerator is cleaned up. var trs = new TaskCompletionSource <object>(state, creationOptions); trs.Task.ContinueWith(_ => enumerator.Dispose(), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); // This will be called every time more work can be done. Action <Task> recursiveBody = null; recursiveBody = antecedent => { try { // If we should continue iterating and there's more to iterate // over, create a continuation to continue processing. We only // want to continue processing once the current Task (as yielded // from the enumerator) is complete. if (enumerator.MoveNext()) { var nextItem = enumerator.Current; // If we got a Task, continue from it to continue iterating if (nextItem is Task) { var nextTask = (Task)nextItem; nextTask.IgnoreExceptions(); // TODO: Is this a good idea? nextTask.ContinueWith(recursiveBody).IgnoreExceptions(); } //// If we got a scheduler, continue iterating under the new scheduler, //// enabling hopping between contexts. else if (nextItem is TaskScheduler) { Task.Factory.StartNew(() => recursiveBody(null), CancellationToken.None, TaskCreationOptions.None, (TaskScheduler)nextItem).IgnoreExceptions(); } //// Anything else is invalid else { trs.TrySetException(new InvalidOperationException("Task or TaskScheduler object expected in Iterate")); } } //// Otherwise, we're done! else { trs.TrySetResult(null); } } //// If MoveNext throws an exception, propagate that to the user, //// either as cancellation or as a fault catch (Exception exc) { var oce = exc as OperationCanceledException; if (oce != null && oce.CancellationToken == cancellationToken) { trs.TrySetCanceled(); } else { trs.TrySetException(exc); } } }; // Get things started by launching the first task factory.StartNew(() => recursiveBody(null), CancellationToken.None, TaskCreationOptions.None, scheduler).IgnoreExceptions(); // Return the representative task to the user return(trs.Task); }