// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // // // A task that produces a value. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System; using System.Collections.Generic; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Security; using System.Security.Permissions; using System.Threading; using System.Diagnostics; using System.Diagnostics.Contracts; // Disable the "reference to volatile field not treated as volatile" error. #pragma warning disable 0420 namespace System.Threading.Tasks { /// /// Represents an asynchronous operation that produces a result at some time in the future. /// /// /// The type of the result produced by this . /// /// /// /// instances may be created in a variety of ways. The most common approach is by /// using the task's property to retrieve a instance that can be used to create tasks for several /// purposes. For example, to create a that runs a function, the factory's StartNew /// method may be used: /// /// // C# /// var t = Task<int>.Factory.StartNew(() => GenerateResult()); /// - or - /// var t = Task.Factory.StartNew(() => GenerateResult()); /// /// ' Visual Basic /// Dim t = Task<int>.Factory.StartNew(Function() GenerateResult()) /// - or - /// Dim t = Task.Factory.StartNew(Function() GenerateResult()) /// /// /// /// The class also provides constructors that initialize the task but that do not /// schedule it for execution. For performance reasons, the StartNew method should be the /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation /// and scheduling must be separated, the constructors may be used, and the task's /// Start /// method may then be used to schedule the task for execution at a later time. /// /// /// All members of , except for /// Dispose, are thread-safe /// and may be used from multiple threads concurrently. /// /// [HostProtection(Synchronization = true, ExternalThreading = true)] [DebuggerTypeProxy(typeof(SystemThreadingTasks_FutureDebugView<>))] [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")] public class Task : Task #if SUPPORT_IOBSERVABLE , IObservable #endif { internal TResult m_result; // The value itself, if set. private static readonly TaskFactory s_Factory = new TaskFactory(); // Delegate used by: // public static Task> WhenAny(IEnumerable> tasks); // public static Task> WhenAny(params Task[] tasks); // Used to "cast" from Task to Task>. internal static readonly Func, Task> TaskWhenAnyCast = completed => (Task)completed.Result; // Construct a promise-style task without any options. internal Task() : base() { } // Construct a promise-style task with state and options. internal Task(object state, TaskCreationOptions options) : base(state, options, promiseStyle:true) { } // Construct a pre-completed Task internal Task(TResult result) : base(false, TaskCreationOptions.None, default(CancellationToken)) { m_result = result; } internal Task(bool canceled, TResult result, TaskCreationOptions creationOptions, CancellationToken ct) : base(canceled, creationOptions, ct) { if (!canceled) { m_result = result; } } // Uncomment if/when we want Task.FromException //// Construct a pre-faulted Task //internal Task(Exception exception) // : base(exception) //{ //} /// /// Initializes a new with the specified function. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function) : this(function, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified function. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// The to be assigned to this task. /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, CancellationToken cancellationToken) : this(function, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified function and creation options. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// /// The TaskCreationOptions used to /// customize the task's behavior. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for . /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, TaskCreationOptions creationOptions) : this(function, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified function and creation options. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// The that will be assigned to the new task. /// /// The TaskCreationOptions used to /// customize the task's behavior. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for . /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(function, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified function and state. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// An object representing data to be used by the action. /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, object state) : this(function, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified action, state, and options. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// An object representing data to be used by the function. /// The to be assigned to the new task. /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, object state, CancellationToken cancellationToken) : this(function, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified action, state, and options. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// An object representing data to be used by the function. /// /// The TaskCreationOptions used to /// customize the task's behavior. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for . /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, object state, TaskCreationOptions creationOptions) : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } /// /// Initializes a new with the specified action, state, and options. /// /// /// The delegate that represents the code to execute in the task. When the function has completed, /// the task's property will be set to return the result value of the function. /// /// An object representing data to be used by the function. /// The to be assigned to the new task. /// /// The TaskCreationOptions used to /// customize the task's behavior. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for . /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; PossiblyCaptureContext(ref stackMark); } internal Task( Func valueSelector, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) : this(valueSelector, parent, cancellationToken, creationOptions, internalOptions, scheduler) { PossiblyCaptureContext(ref stackMark); } /// /// Creates a new future object. /// /// The parent task for this future. /// A function that yields the future value. /// The task scheduler which will be used to execute the future. /// The CancellationToken for the task. /// Options to control the future's behavior. /// Internal options to control the future's behavior. /// The argument specifies /// a SelfReplicating , which is illegal."/>. internal Task(Func valueSelector, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler) { if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) { throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating")); } } internal Task( Func valueSelector, object state, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) : this(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) { PossiblyCaptureContext(ref stackMark); } /// /// Creates a new future object. /// /// The parent task for this future. /// An object containing data to be used by the action; may be null. /// A function that yields the future value. /// The CancellationToken for the task. /// The task scheduler which will be used to execute the future. /// Options to control the future's behavior. /// Internal options to control the future's behavior. /// The argument specifies /// a SelfReplicating , which is illegal."/>. internal Task(Delegate valueSelector, object state, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) { if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) { throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating")); } } // Internal method used by TaskFactory.StartNew() methods internal static Task StartNew(Task parent, Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) { if (function == null) { throw new ArgumentNullException("function"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) { throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating")); } // Create and schedule the future. Task f = new Task(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark); f.ScheduleAndStart(false); return f; } // Internal method used by TaskFactory.StartNew() methods internal static Task StartNew(Task parent, Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) { if (function == null) { throw new ArgumentNullException("function"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) { throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating")); } // Create and schedule the future. Task f = new Task(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark); f.ScheduleAndStart(false); return f; } // Debugger support private string DebuggerDisplayResultDescription { get { return IsRanToCompletion ? "" + m_result : Environment.GetResourceString("TaskT_DebuggerNoResult"); } } // Debugger support private string DebuggerDisplayMethodDescription { get { Delegate d = (Delegate)m_action; return d != null ? d.Method.ToString() : "{null}"; } } // internal helper function breaks out logic used by TaskCompletionSource internal bool TrySetResult(TResult result) { if (IsCompleted) return false; Contract.Assert(m_action == null, "Task.TrySetResult(): non-null m_action"); // "Reserve" the completion for this task, while making sure that: (1) No prior reservation // has been made, (2) The result has not already been set, (3) An exception has not previously // been recorded, and (4) Cancellation has not been requested. // // If the reservation is successful, then set the result and finish completion processing. if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) { m_result = result; // Signal completion, for waiting tasks // This logic used to be: // Finish(false); // However, that goes through a windy code path, involves many non-inlineable functions // and which can be summarized more concisely with the following snippet from // FinishStageTwo, omitting everything that doesn't pertain to TrySetResult. Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION); var cp = m_contingentProperties; if (cp != null) cp.SetCompleted(); FinishStageThree(); return true; } return false; } // Transitions the promise task into a successfully completed state with the specified result. // This is dangerous, as no synchronization is used, and thus must only be used // before this task is handed out to any consumers, before any continuations are hooked up, // before its wait handle is accessed, etc. It's use is limited to places like in FromAsync // where the operation completes synchronously, and thus we know we can forcefully complete // the task, avoiding expensive completion paths, before the task is actually given to anyone. internal void DangerousSetResult(TResult result) { Contract.Assert(!IsCompleted, "The promise must not yet be completed."); // If we have a parent, we need to notify it of the completion. Take the slow path to handle that. if (m_parent != null) { bool success = TrySetResult(result); // Nobody else has had a chance to complete this Task yet, so we should succeed. Contract.Assert(success); } else { m_result = result; m_stateFlags |= TASK_STATE_RAN_TO_COMPLETION; } } /// /// Gets the result value of this . /// /// /// The get accessor for this property ensures that the asynchronous operation is complete before /// returning. Once the result of the computation is available, it is stored and will be returned /// immediately on later calls to . /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] public TResult Result { get { return IsWaitNotificationEnabledOrNotRanToCompletion ? GetResultCore(waitCompletionNotification: true) : m_result; } } /// /// Gets the result value of this once the task has completed successfully. /// /// /// This version of Result should only be used if the task completed successfully and if there's /// no debugger wait notification enabled for this task. /// internal TResult ResultOnSuccess { get { Contract.Assert(!IsWaitNotificationEnabledOrNotRanToCompletion, "Should only be used when the task completed successfully and there's no wait notification enabled"); return m_result; } } // Implements Result. Result delegates to this method if the result isn't already available. internal TResult GetResultCore(bool waitCompletionNotification) { // If the result has not been calculated yet, wait for it. if (!IsCompleted) InternalWait(Timeout.Infinite, default(CancellationToken)); // won't throw if task faulted or canceled; that's handled below // Notify the debugger of the wait completion if it's requested such a notification if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary(); // Throw an exception if appropriate. if (!IsRanToCompletion) ThrowIfExceptional(includeTaskCanceledExceptions: true); // We shouldn't be here if the result has not been set. Contract.Assert(IsRanToCompletion, "Task.Result getter: Expected result to have been set."); return m_result; } // Allow multiple exceptions to be assigned to a promise-style task. // This is useful when a TaskCompletionSource stands in as a proxy // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll()) // and the "real" task ends up with multiple exceptions, which is possible when // a task has children. // // Called from TaskCompletionSource.SetException(IEnumerable). internal bool TrySetException(object exceptionObject) { Contract.Assert(m_action == null, "Task.TrySetException(): non-null m_action"); // TCS.{Try}SetException() should have checked for this Contract.Assert(exceptionObject != null, "Expected non-null exceptionObject argument"); // Only accept these types. Contract.Assert( (exceptionObject is Exception) || (exceptionObject is IEnumerable) || (exceptionObject is ExceptionDispatchInfo) || (exceptionObject is IEnumerable), "Expected exceptionObject to be either Exception, ExceptionDispatchInfo, or IEnumerable<> of one of those"); bool returnValue = false; // "Reserve" the completion for this task, while making sure that: (1) No prior reservation // has been made, (2) The result has not already been set, (3) An exception has not previously // been recorded, and (4) Cancellation has not been requested. // // If the reservation is successful, then add the exception(s) and finish completion processing. // // The lazy initialization may not be strictly necessary, but I'd like to keep it here // anyway. Some downstream logic may depend upon an inflated m_contingentProperties. EnsureContingentPropertiesInitialized(needsProtection: true); if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) { AddException(exceptionObject); // handles singleton exception or exception collection Finish(false); returnValue = true; } return returnValue; } // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder // If the tokenToRecord is not None, it will be stored onto the task. // This method is only valid for promise tasks. internal bool TrySetCanceled(CancellationToken tokenToRecord) { return TrySetCanceled(tokenToRecord, null); } // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder // If the tokenToRecord is not None, it will be stored onto the task. // If the OperationCanceledException is not null, it will be stored into the task's exception holder. // This method is only valid for promise tasks. internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException) { Contract.Assert(m_action == null, "Task.TrySetCanceled(): non-null m_action"); #if DEBUG var ceAsEdi = cancellationException as ExceptionDispatchInfo; Contract.Assert( cancellationException == null || cancellationException is OperationCanceledException || (ceAsEdi != null && ceAsEdi.SourceException is OperationCanceledException), "Expected null or an OperationCanceledException"); #endif bool returnValue = false; // "Reserve" the completion for this task, while making sure that: (1) No prior reservation // has been made, (2) The result has not already been set, (3) An exception has not previously // been recorded, and (4) Cancellation has not been requested. // // If the reservation is successful, then record the cancellation and finish completion processing. // // Note: I had to access static Task variables through Task // instead of Task, because I have a property named Task and that // was confusing the compiler. if (AtomicStateUpdate(Task.TASK_STATE_COMPLETION_RESERVED, Task.TASK_STATE_COMPLETION_RESERVED | Task.TASK_STATE_CANCELED | Task.TASK_STATE_FAULTED | Task.TASK_STATE_RAN_TO_COMPLETION)) { RecordInternalCancellationRequest(tokenToRecord, cancellationException); CancellationCleanupLogic(); // perform cancellation cleanup actions returnValue = true; } return returnValue; } /// /// Provides access to factory methods for creating instances. /// /// /// The factory returned from is a default instance /// of , as would result from using /// the default constructor on the factory type. /// public new static TaskFactory Factory { get { return s_Factory; } } /// /// Evaluates the value selector of the Task which is passed in as an object and stores the result. /// internal override void InnerInvoke() { // Invoke the delegate Contract.Assert(m_action != null); var func = m_action as Func; if (func != null) { m_result = func(); return; } var funcWithState = m_action as Func; if (funcWithState != null) { m_result = funcWithState(m_stateObject); return; } Contract.Assert(false, "Invalid m_action in Task"); } #region Await Support /// Gets an awaiter used to await this . /// An awaiter instance. /// This method is intended for compiler user rather than use directly in code. public new TaskAwaiter GetAwaiter() { return new TaskAwaiter(this); } /// Configures an awaiter used to await this . /// /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. /// /// An object used to await this task. public new ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { return new ConfiguredTaskAwaitable(this, continueOnCapturedContext); } #endregion #region Continuation methods #region Action> continuations /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark); } // Same as the above overload, only with a stack mark. internal Task ContinueWith(Action> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( this, continuationAction, null, creationOptions, internalOptions, ref stackMark ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion #region Action, Object> continuations /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, Object> continuationAction, Object state) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, Object> continuationAction, Object state,CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, Object> continuationAction, Object state, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, Object> continuationAction, Object state,TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, Object> continuationAction, Object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark); } // Same as the above overload, only with a stack mark. internal Task ContinueWith(Action, Object> continuationAction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( this, continuationAction, state, creationOptions, internalOptions, ref stackMark ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } #endregion #region Func,TNewResult> continuations /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . This task's completion state will be transferred to the task returned /// from the ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be passed as /// an argument this completed task. /// /// The that will be assigned to the new task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . /// This task's completion state will be transferred to the task returned from the /// ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark); } // Same as the above overload, just with a stack mark. internal Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, null, creationOptions, internalOptions, ref stackMark ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); return continuationFuture; } #endregion #region Func, Object,TNewResult> continuations /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state, CancellationToken cancellationToken) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . This task's completion state will be transferred to the task returned /// from the ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state, TaskContinuationOptions continuationOptions) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . /// This task's completion state will be transferred to the task returned from the /// ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; return ContinueWith(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark); } // Same as the above overload, just with a stack mark. internal Task ContinueWith(Func, Object, TNewResult> continuationFunction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, state, creationOptions, internalOptions, ref stackMark ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); return continuationFuture; } #endregion #endregion /// /// Subscribes an to receive notification of the final state of this . /// /// /// The to call on task completion. If this Task throws an exception, /// observer.OnError is called with this Task's AggregateException. If this Task RanToCompletion, /// observer.OnNext is called with this Task's result, followed by a call to observer.OnCompleted. /// If this Task is Canceled, observer.OnError is called with a TaskCanceledException /// containing this Task's CancellationToken /// /// An IDisposable object . /// /// The argument is null. /// #if SUPPORT_IOBSERVABLE IDisposable IObservable.Subscribe(IObserver observer) { if (observer == null) throw new System.ArgumentNullException("observer"); var continuationTask = this.ContinueWith(delegate(Task observedTask, object taskObserverObject) { IObserver taskObserver = (IObserver)taskObserverObject; if (observedTask.IsFaulted) taskObserver.OnError(observedTask.Exception); else if (observedTask.IsCanceled) taskObserver.OnError(new TaskCanceledException(observedTask)); else { taskObserver.OnNext(observedTask.Result); taskObserver.OnCompleted(); } }, observer, TaskScheduler.Default); return new DisposableSubscription(this, continuationTask); } #endif } #if SUPPORT_IOBSERVABLE // Class that calls RemoveContinuation if Dispose() is called before task completion internal class DisposableSubscription : IDisposable { private Task _notifyObserverContinuationTask; private Task _observedTask; internal DisposableSubscription(Task observedTask, Task notifyObserverContinuationTask) { _observedTask = observedTask; _notifyObserverContinuationTask = notifyObserverContinuationTask; } void IDisposable.Dispose() { Task localObservedTask = _observedTask; Task localNotifyingContinuationTask = _notifyObserverContinuationTask; if (localObservedTask != null && localNotifyingContinuationTask != null && !localObservedTask.IsCompleted) { localObservedTask.RemoveContinuation(localNotifyingContinuationTask); } _observedTask = null; _notifyObserverContinuationTask = null; } } #endif // Proxy class for better debugging experience internal class SystemThreadingTasks_FutureDebugView { private Task m_task; public SystemThreadingTasks_FutureDebugView(Task task) { m_task = task; } public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default(TResult); } } public object AsyncState { get { return m_task.AsyncState; } } public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } public Exception Exception { get { return m_task.Exception; } } public int Id { get { return m_task.Id; } } public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } } public TaskStatus Status { get { return m_task.Status; } } } }