5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (c) 2008 Jérémie "Garuma" Laval
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 using System.Threading;
34 using System.Collections.Concurrent;
35 using System.Runtime.CompilerServices;
37 namespace System.Threading.Tasks
39 [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
40 [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
41 public class Task : IDisposable, IAsyncResult
43 // With this attribute each thread has its own value so that it's correct for our Schedule code
44 // and for Parent property.
48 static Action<Task> childWorkAdder;
53 static readonly TaskFactory defaultFactory = new TaskFactory ();
54 internal static readonly Task Finished = new Task (TaskStatus.RanToCompletion);
55 internal static readonly Task Canceled = new Task (TaskStatus.Canceled);
57 CountdownEvent childTasks = new CountdownEvent (1);
60 TaskCreationOptions taskCreationOptions;
62 TaskScheduler scheduler;
64 ManualResetEventSlim schedWait = new ManualResetEventSlim (false);
66 volatile AggregateException exception;
67 volatile bool exceptionObserved;
68 ConcurrentQueue<AggregateException> childExceptions;
72 Action<object> action;
75 AtomicBooleanValue executing;
77 ConcurrentQueue<EventHandler> completed;
79 CancellationToken token;
81 const TaskCreationOptions MaxTaskCreationOptions =
82 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
84 public Task (Action action) : this (action, TaskCreationOptions.None)
89 public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
94 public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
99 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
100 : this (null, null, cancellationToken, creationOptions, current)
103 throw new ArgumentNullException ("action");
104 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
105 throw new ArgumentOutOfRangeException ("creationOptions");
106 this.simpleAction = action;
109 public Task (Action<object> action, object state) : this (action, state, TaskCreationOptions.None)
113 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
114 : this (action, state, CancellationToken.None, creationOptions)
118 public Task (Action<object> action, object state, CancellationToken cancellationToken)
119 : this (action, state, cancellationToken, TaskCreationOptions.None)
123 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
124 : this (action, state, cancellationToken, creationOptions, current)
127 throw new ArgumentNullException ("action");
128 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
129 throw new ArgumentOutOfRangeException ("creationOptions");
132 internal Task (Action<object> action,
134 CancellationToken cancellationToken,
135 TaskCreationOptions creationOptions,
138 this.taskCreationOptions = creationOptions;
139 this.action = action;
141 this.taskId = Interlocked.Increment (ref id);
142 this.status = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
143 this.token = cancellationToken;
144 this.parent = parent;
146 // Process taskCreationOptions
147 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
151 internal Task (TaskStatus status)
153 this.status = status;
158 if (exception != null && !exceptionObserved)
162 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
164 return (opt & member) == member;
170 Start (TaskScheduler.Current);
173 public void Start (TaskScheduler scheduler)
175 if (status >= TaskStatus.WaitingToRun)
176 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
177 SetupScheduler (scheduler);
181 internal void SetupScheduler (TaskScheduler scheduler)
183 this.scheduler = scheduler;
184 status = TaskStatus.WaitingForActivation;
188 public void RunSynchronously ()
190 RunSynchronously (TaskScheduler.Current);
193 public void RunSynchronously (TaskScheduler scheduler)
195 if (scheduler == null)
196 throw new ArgumentNullException ("scheduler");
198 if (Status > TaskStatus.WaitingForActivation)
199 throw new InvalidOperationException ("The task is not in a valid state to be started");
201 SetupScheduler (scheduler);
202 var saveStatus = status;
203 status = TaskStatus.WaitingToRun;
206 if (scheduler.RunInline (this))
208 } catch (Exception inner) {
209 throw new TaskSchedulerException (inner);
219 public Task ContinueWith (Action<Task> continuationAction)
221 return ContinueWith (continuationAction, TaskContinuationOptions.None);
224 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
226 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
229 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
231 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
234 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
236 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
239 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
241 if (continuationAction == null)
242 throw new ArgumentNullException ("continuationAction");
243 if (scheduler == null)
244 throw new ArgumentNullException ("scheduler");
246 Task continuation = new Task (l => continuationAction ((Task)l),
249 GetCreationOptions (continuationOptions),
251 ContinueWithCore (continuation, continuationOptions, scheduler);
256 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
258 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
261 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
263 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
266 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
268 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
271 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
273 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
276 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
277 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
279 if (continuationFunction == null)
280 throw new ArgumentNullException ("continuationFunction");
281 if (scheduler == null)
282 throw new ArgumentNullException ("scheduler");
284 Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
287 GetCreationOptions (continuationOptions),
290 ContinueWithCore (t, continuationOptions, scheduler);
295 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
297 ContinueWithCore (continuation, continuationOptions, scheduler, null);
300 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
301 TaskScheduler scheduler, Func<bool> predicate)
303 // Already set the scheduler so that user can call Wait and that sort of stuff
304 continuation.scheduler = scheduler;
305 continuation.schedWait.Set ();
306 continuation.status = TaskStatus.WaitingForActivation;
308 AtomicBoolean launched = new AtomicBoolean ();
309 EventHandler action = delegate (object sender, EventArgs e) {
310 if (launched.TryRelaxedSet ()) {
311 if (predicate != null && !predicate ())
314 if (!ContinuationStatusCheck (kind)) {
315 continuation.CancelReal ();
316 continuation.Dispose ();
321 CheckAndSchedule (continuation, kind, scheduler, sender == null);
326 action (null, EventArgs.Empty);
330 if (completed == null)
331 Interlocked.CompareExchange (ref completed, new ConcurrentQueue<EventHandler> (), null);
332 completed.Enqueue (action);
334 // Retry in case completion was achieved but event adding was too late
336 action (null, EventArgs.Empty);
340 bool ContinuationStatusCheck (TaskContinuationOptions kind)
342 if (kind == TaskContinuationOptions.None)
345 int kindCode = (int)kind;
347 if (kindCode >= ((int)TaskContinuationOptions.NotOnRanToCompletion)) {
348 // Remove other options
349 kind &= ~(TaskContinuationOptions.PreferFairness
350 | TaskContinuationOptions.LongRunning
351 | TaskContinuationOptions.AttachedToParent
352 | TaskContinuationOptions.ExecuteSynchronously);
354 if (status == TaskStatus.Canceled) {
355 if (kind == TaskContinuationOptions.NotOnCanceled)
357 if (kind == TaskContinuationOptions.OnlyOnFaulted)
359 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
361 } else if (status == TaskStatus.Faulted) {
362 if (kind == TaskContinuationOptions.NotOnFaulted)
364 if (kind == TaskContinuationOptions.OnlyOnCanceled)
366 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
368 } else if (status == TaskStatus.RanToCompletion) {
369 if (kind == TaskContinuationOptions.NotOnRanToCompletion)
371 if (kind == TaskContinuationOptions.OnlyOnFaulted)
373 if (kind == TaskContinuationOptions.OnlyOnCanceled)
381 void CheckAndSchedule (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler, bool fromCaller)
383 if ((options & TaskContinuationOptions.ExecuteSynchronously) > 0)
384 continuation.RunSynchronously (scheduler);
386 continuation.Start (scheduler);
389 internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
391 TaskCreationOptions options = TaskCreationOptions.None;
392 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
393 options |= TaskCreationOptions.AttachedToParent;
394 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
395 options |= TaskCreationOptions.PreferFairness;
396 if ((kind & TaskContinuationOptions.LongRunning) > 0)
397 options |= TaskCreationOptions.LongRunning;
403 #region Internal and protected thingies
404 internal void Schedule ()
406 status = TaskStatus.WaitingToRun;
408 // If worker is null it means it is a local one, revert to the old behavior
409 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
410 if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
411 scheduler.QueueTask (this);
413 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
414 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
415 * the correct Thread during the creation
417 childWorkAdder (this);
423 /* Allow scheduler to break fairness of deque ordering without
424 * breaking its semantic (the task can be executed twice but the
425 * second time it will return immediately
427 if (!executing.TryRelaxedSet ())
431 TaskScheduler.Current = scheduler;
433 if (!token.IsCancellationRequested) {
435 status = TaskStatus.Running;
439 } catch (OperationCanceledException oce) {
440 if (token != CancellationToken.None && oce.CancellationToken == token)
443 HandleGenericException (oce);
444 } catch (Exception e) {
445 HandleGenericException (e);
454 internal void Execute (Action<Task> childAdder)
456 childWorkAdder = childAdder;
460 internal void AddChild ()
462 childTasks.AddCount ();
465 internal void ChildCompleted (AggregateException childEx)
467 if (childEx != null) {
468 if (childExceptions == null)
469 Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
470 childExceptions.Enqueue (childEx);
473 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
474 status = TaskStatus.RanToCompletion;
475 ProcessChildExceptions ();
476 ProcessCompleteDelegates ();
480 internal virtual void InnerInvoke ()
482 if (action == null && simpleAction != null)
484 else if (action != null)
486 // Set action to null so that the GC can collect the delegate and thus
487 // any big object references that the user might have captured in an anonymous method
493 internal void Finish ()
495 // If there wasn't any child created in the task we set the CountdownEvent
496 childTasks.Signal ();
498 // Don't override Canceled or Faulted
499 if (status == TaskStatus.Running) {
500 if (childTasks.IsSet)
501 status = TaskStatus.RanToCompletion;
503 status = TaskStatus.WaitingForChildrenToComplete;
506 if (status != TaskStatus.WaitingForChildrenToComplete)
507 ProcessCompleteDelegates ();
509 // Reset the current thingies
511 TaskScheduler.Current = null;
513 // Tell parent that we are finished
514 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
515 parent.ChildCompleted (this.Exception);
519 void ProcessCompleteDelegates ()
521 if (completed == null)
524 EventHandler handler;
525 while (completed.TryDequeue (out handler))
526 handler (this, EventArgs.Empty);
529 void ProcessChildExceptions ()
531 if (childExceptions == null)
534 if (exception == null)
535 exception = new AggregateException ();
537 AggregateException childEx;
538 while (childExceptions.TryDequeue (out childEx))
539 exception.AddChildException (childEx);
543 #region Cancel and Wait related method
545 internal void CancelReal ()
547 status = TaskStatus.Canceled;
550 internal void HandleGenericException (Exception e)
552 HandleGenericException (new AggregateException (e));
555 internal void HandleGenericException (AggregateException e)
558 Thread.MemoryBarrier ();
559 status = TaskStatus.Faulted;
560 if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
561 exceptionObserved = true;
566 if (scheduler == null)
570 scheduler.ParticipateUntil (this);
571 if (exception != null)
574 throw new AggregateException (new TaskCanceledException (this));
577 public void Wait (CancellationToken cancellationToken)
579 Wait (-1, cancellationToken);
582 public bool Wait (TimeSpan timeout)
584 return Wait (CheckTimeout (timeout), CancellationToken.None);
587 public bool Wait (int millisecondsTimeout)
589 return Wait (millisecondsTimeout, CancellationToken.None);
592 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
594 if (millisecondsTimeout < -1)
595 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
597 if (millisecondsTimeout == -1 && token == CancellationToken.None) {
602 Watch watch = Watch.StartNew ();
604 if (scheduler == null) {
605 schedWait.Wait (millisecondsTimeout, cancellationToken);
606 millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
609 ManualResetEventSlim predicateEvt = new ManualResetEventSlim (false);
610 if (cancellationToken != CancellationToken.None) {
611 cancellationToken.Register (predicateEvt.Set);
612 cancellationToken.ThrowIfCancellationRequested ();
615 bool result = scheduler.ParticipateUntil (this, predicateEvt, millisecondsTimeout);
617 if (exception != null)
620 throw new AggregateException (new TaskCanceledException (this));
625 public static void WaitAll (params Task[] tasks)
628 throw new ArgumentNullException ("tasks");
630 foreach (var t in tasks) {
632 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
637 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
640 throw new ArgumentNullException ("tasks");
642 foreach (var t in tasks) {
644 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
646 t.Wait (cancellationToken);
650 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
653 throw new ArgumentNullException ("tasks");
656 foreach (var t in tasks) {
658 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
660 result &= t.Wait (timeout);
665 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
668 throw new ArgumentNullException ("tasks");
671 foreach (var t in tasks) {
673 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
675 result &= t.Wait (millisecondsTimeout);
680 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
683 throw new ArgumentNullException ("tasks");
686 foreach (var t in tasks) {
688 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
690 result &= t.Wait (millisecondsTimeout, cancellationToken);
695 public static int WaitAny (params Task[] tasks)
697 return WaitAny (tasks, -1, CancellationToken.None);
700 public static int WaitAny (Task[] tasks, TimeSpan timeout)
702 return WaitAny (tasks, CheckTimeout (timeout));
705 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
707 if (millisecondsTimeout < -1)
708 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
710 if (millisecondsTimeout == -1)
711 return WaitAny (tasks);
713 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
716 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
718 return WaitAny (tasks, -1, cancellationToken);
721 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
724 throw new ArgumentNullException ("tasks");
725 if (tasks.Length == 0)
726 throw new ArgumentException ("tasks is empty", "tasks");
727 if (tasks.Length == 1) {
728 tasks[0].Wait (millisecondsTimeout, cancellationToken);
733 int indexFirstFinished = -1;
735 TaskScheduler sched = null;
737 Watch watch = Watch.StartNew ();
738 ManualResetEventSlim predicateEvt = new ManualResetEventSlim (false);
740 foreach (Task t in tasks) {
741 int indexResult = index++;
742 t.ContinueWith (delegate {
743 if (numFinished >= 1)
745 int result = Interlocked.Increment (ref numFinished);
747 // Check if we are the first to have finished
749 indexFirstFinished = indexResult;
753 }, TaskContinuationOptions.ExecuteSynchronously);
755 if (sched == null && t.scheduler != null) {
761 // If none of task have a scheduler we are forced to wait for at least one to start
763 var handles = Array.ConvertAll (tasks, t => t.schedWait.WaitHandle);
765 if ((shandle = WaitHandle.WaitAny (handles, millisecondsTimeout)) == WaitHandle.WaitTimeout)
767 sched = tasks[shandle].scheduler;
768 task = tasks[shandle];
769 millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
772 // One task already finished
773 if (indexFirstFinished != -1)
774 return indexFirstFinished;
776 if (cancellationToken != CancellationToken.None) {
777 cancellationToken.Register (predicateEvt.Set);
778 cancellationToken.ThrowIfCancellationRequested ();
781 sched.ParticipateUntil (task, predicateEvt, millisecondsTimeout);
783 // Index update is still not done
784 if (indexFirstFinished == -1) {
785 SpinWait wait = new SpinWait ();
786 while (indexFirstFinished == -1)
790 return indexFirstFinished;
793 static int CheckTimeout (TimeSpan timeout)
796 return checked ((int)timeout.TotalMilliseconds);
797 } catch (System.OverflowException) {
798 throw new ArgumentOutOfRangeException ("timeout");
802 static int ComputeTimeout (int millisecondsTimeout, Watch watch)
804 return millisecondsTimeout == -1 ? -1 : (int)Math.Max (watch.ElapsedMilliseconds - millisecondsTimeout, 1);
810 public void Dispose ()
815 protected virtual void Dispose (bool disposing)
818 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
820 // Set action to null so that the GC can collect the delegate and thus
821 // any big object references that the user might have captured in a anonymous method
831 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
833 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
836 public Task ContinueWith (Action<Task, object> continuationAction, object state)
838 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
841 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
843 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
846 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
848 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
851 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
853 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
856 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
857 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
859 if (continuationAction == null)
860 throw new ArgumentNullException ("continuationAction");
861 if (scheduler == null)
862 throw new ArgumentNullException ("scheduler");
864 Task continuation = new Task (l => continuationAction (this, l), state,
866 GetCreationOptions (continuationOptions),
868 ContinueWithCore (continuation, continuationOptions, scheduler);
873 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
875 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
878 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
880 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
883 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
885 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
888 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
890 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
893 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
894 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
896 if (continuationFunction == null)
897 throw new ArgumentNullException ("continuationFunction");
898 if (scheduler == null)
899 throw new ArgumentNullException ("scheduler");
901 var t = new Task<TResult> (l => continuationFunction (this, l),
904 GetCreationOptions (continuationOptions),
907 ContinueWithCore (t, continuationOptions, scheduler);
912 public static Task<TResult> FromResult<TResult> (TResult result)
914 var t = new Task<TResult> (TaskStatus.RanToCompletion);
919 public TaskAwaiter GetAwaiter ()
921 return new TaskAwaiter (this);
924 public static YieldAwaitable Yield ()
926 return new YieldAwaitable ();
931 public static TaskFactory Factory {
933 return defaultFactory;
937 public static int? CurrentId {
940 return t == null ? (int?)null : t.Id;
944 public AggregateException Exception {
946 exceptionObserved = true;
955 public bool IsCanceled {
957 return status == TaskStatus.Canceled;
961 public bool IsCompleted {
963 return status == TaskStatus.RanToCompletion ||
964 status == TaskStatus.Canceled || status == TaskStatus.Faulted;
968 public bool IsFaulted {
970 return status == TaskStatus.Faulted;
974 public TaskCreationOptions CreationOptions {
976 return taskCreationOptions;
980 public TaskStatus Status {
989 public object AsyncState {
995 bool IAsyncResult.CompletedSynchronously {
1001 WaitHandle IAsyncResult.AsyncWaitHandle {
1013 internal Task Parent {
1019 internal string DisplayActionMethod {
1021 Delegate d = simpleAction ?? (Delegate) action;
1022 return d == null ? "<none>" : d.Method.ToString ();