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.Collections.Generic;
36 using System.Runtime.CompilerServices;
38 namespace System.Threading.Tasks
40 [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
41 [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
42 public class Task : IDisposable, IAsyncResult
44 // With this attribute each thread has its own value so that it's correct for our Schedule code
45 // and for Parent property.
49 static Action<Task> childWorkAdder;
54 static readonly TaskFactory defaultFactory = new TaskFactory ();
56 CountdownEvent childTasks;
59 TaskCreationOptions taskCreationOptions;
61 TaskScheduler scheduler;
63 ManualResetEventSlim schedWait = new ManualResetEventSlim (false);
65 volatile AggregateException exception;
66 volatile bool exceptionObserved;
67 ConcurrentQueue<AggregateException> childExceptions;
71 Action<object> action;
74 AtomicBooleanValue executing;
76 CompletionContainer completed;
77 // If this task is a continuation, this stuff gets filled
80 CancellationToken token;
81 CancellationTokenRegistration? cancelation_registration;
83 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
85 const TaskCreationOptions MaxTaskCreationOptions =
87 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
89 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
91 public Task (Action action) : this (action, TaskCreationOptions.None)
96 public Task (Action action, TaskCreationOptions creationOptions) : this (action, CancellationToken.None, creationOptions)
101 public Task (Action action, CancellationToken cancellationToken) : this (action, cancellationToken, TaskCreationOptions.None)
106 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107 : this (null, null, cancellationToken, creationOptions, current)
110 throw new ArgumentNullException ("action");
111 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
112 throw new ArgumentOutOfRangeException ("creationOptions");
113 this.simpleAction = action;
116 public Task (Action<object> action, object state) : this (action, state, TaskCreationOptions.None)
120 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
121 : this (action, state, CancellationToken.None, creationOptions)
125 public Task (Action<object> action, object state, CancellationToken cancellationToken)
126 : this (action, state, cancellationToken, TaskCreationOptions.None)
130 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
131 : this (action, state, cancellationToken, creationOptions, current)
134 throw new ArgumentNullException ("action");
135 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
136 throw new ArgumentOutOfRangeException ("creationOptions");
139 internal Task (Action<object> action,
141 CancellationToken cancellationToken,
142 TaskCreationOptions creationOptions,
145 this.taskCreationOptions = creationOptions;
146 this.action = action;
148 this.taskId = Interlocked.Increment (ref id);
149 this.status = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
150 this.token = cancellationToken;
151 this.parent = parent;
153 // Process taskCreationOptions
154 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
157 if (token.CanBeCanceled) {
158 cancelation_registration = token.Register (l => ((Task) l).CancelReal (), this);
164 if (exception != null && !exceptionObserved)
168 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
170 return (opt & member) == member;
176 Start (TaskScheduler.Current);
179 public void Start (TaskScheduler scheduler)
181 if (scheduler == null)
182 throw new ArgumentNullException ("scheduler");
184 if (status >= TaskStatus.WaitingToRun)
185 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
187 if (Slot.Initialized)
188 throw new InvalidOperationException ("Start may not be called on a continuation task");
190 SetupScheduler (scheduler);
194 internal void SetupScheduler (TaskScheduler scheduler)
196 this.scheduler = scheduler;
197 status = TaskStatus.WaitingForActivation;
201 public void RunSynchronously ()
203 RunSynchronously (TaskScheduler.Current);
206 public void RunSynchronously (TaskScheduler scheduler)
208 if (scheduler == null)
209 throw new ArgumentNullException ("scheduler");
211 if (Status > TaskStatus.WaitingForActivation)
212 throw new InvalidOperationException ("The task is not in a valid state to be started");
214 SetupScheduler (scheduler);
215 var saveStatus = status;
216 status = TaskStatus.WaitingToRun;
219 if (scheduler.RunInline (this))
221 } catch (Exception inner) {
222 throw new TaskSchedulerException (inner);
232 public Task ContinueWith (Action<Task> continuationAction)
234 return ContinueWith (continuationAction, TaskContinuationOptions.None);
237 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
239 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
242 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
244 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
247 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
249 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
252 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
254 if (continuationAction == null)
255 throw new ArgumentNullException ("continuationAction");
256 if (scheduler == null)
257 throw new ArgumentNullException ("scheduler");
259 Task continuation = new Task (l => continuationAction ((Task)l),
262 GetCreationOptions (continuationOptions),
264 ContinueWithCore (continuation, continuationOptions, scheduler);
269 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
271 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
274 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
276 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
279 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
281 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
284 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
286 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
289 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
290 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
292 if (continuationFunction == null)
293 throw new ArgumentNullException ("continuationFunction");
294 if (scheduler == null)
295 throw new ArgumentNullException ("scheduler");
297 Task<TResult> t = new Task<TResult> ((o) => continuationFunction ((Task)o),
300 GetCreationOptions (continuationOptions),
303 ContinueWithCore (t, continuationOptions, scheduler);
308 internal void ContinueWithCore (Task continuation, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
310 ContinueWithCore (continuation, continuationOptions, scheduler, null);
313 internal void ContinueWithCore (Task continuation, TaskContinuationOptions kind,
314 TaskScheduler scheduler, Func<bool> predicate)
316 // Already set the scheduler so that user can call Wait and that sort of stuff
317 continuation.scheduler = scheduler;
318 continuation.schedWait.Set ();
319 continuation.status = TaskStatus.WaitingForActivation;
320 continuation.Slot = new CompletionSlot (kind, predicate);
323 CompletionExecutor (continuation);
327 completed.Add (continuation);
329 // Retry in case completion was achieved but event adding was too late
331 CompletionExecutor (continuation);
335 bool ContinuationStatusCheck (TaskContinuationOptions kind)
337 if (kind == TaskContinuationOptions.None)
340 int kindCode = (int)kind;
342 if (kindCode >= ((int)TaskContinuationOptions.NotOnRanToCompletion)) {
343 // Remove other options
344 kind &= ~(TaskContinuationOptions.PreferFairness
345 | TaskContinuationOptions.LongRunning
346 | TaskContinuationOptions.AttachedToParent
347 | TaskContinuationOptions.ExecuteSynchronously);
349 if (status == TaskStatus.Canceled) {
350 if (kind == TaskContinuationOptions.NotOnCanceled)
352 if (kind == TaskContinuationOptions.OnlyOnFaulted)
354 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
356 } else if (status == TaskStatus.Faulted) {
357 if (kind == TaskContinuationOptions.NotOnFaulted)
359 if (kind == TaskContinuationOptions.OnlyOnCanceled)
361 if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
363 } else if (status == TaskStatus.RanToCompletion) {
364 if (kind == TaskContinuationOptions.NotOnRanToCompletion)
366 if (kind == TaskContinuationOptions.OnlyOnFaulted)
368 if (kind == TaskContinuationOptions.OnlyOnCanceled)
376 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
378 TaskCreationOptions options = TaskCreationOptions.None;
379 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
380 options |= TaskCreationOptions.AttachedToParent;
381 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
382 options |= TaskCreationOptions.PreferFairness;
383 if ((kind & TaskContinuationOptions.LongRunning) > 0)
384 options |= TaskCreationOptions.LongRunning;
390 #region Internal and protected thingies
391 internal void Schedule ()
393 status = TaskStatus.WaitingToRun;
395 // If worker is null it means it is a local one, revert to the old behavior
396 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
397 if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
398 scheduler.QueueTask (this);
400 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
401 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
402 * the correct Thread during the creation
404 childWorkAdder (this);
410 /* Allow scheduler to break fairness of deque ordering without
411 * breaking its semantic (the task can be executed twice but the
412 * second time it will return immediately
414 if (!executing.TryRelaxedSet ())
418 TaskScheduler.Current = scheduler;
420 if (!token.IsCancellationRequested) {
422 status = TaskStatus.Running;
426 } catch (OperationCanceledException oce) {
427 if (token != CancellationToken.None && oce.CancellationToken == token)
430 HandleGenericException (oce);
431 } catch (Exception e) {
432 HandleGenericException (e);
441 internal void Execute (Action<Task> childAdder)
443 childWorkAdder = childAdder;
447 internal void AddChild ()
449 if (childTasks == null)
450 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
451 childTasks.AddCount ();
454 internal void ChildCompleted (AggregateException childEx)
456 if (childEx != null) {
457 if (childExceptions == null)
458 Interlocked.CompareExchange (ref childExceptions, new ConcurrentQueue<AggregateException> (), null);
459 childExceptions.Enqueue (childEx);
462 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
463 status = TaskStatus.RanToCompletion;
464 ProcessChildExceptions ();
465 ProcessCompleteDelegates ();
469 internal virtual void InnerInvoke ()
471 if (action == null && simpleAction != null)
473 else if (action != null)
475 // Set action to null so that the GC can collect the delegate and thus
476 // any big object references that the user might have captured in an anonymous method
482 internal void Finish ()
484 // If there was children created and they all finished, we set the countdown
485 if (childTasks != null)
486 childTasks.Signal ();
488 // Don't override Canceled or Faulted
489 if (status == TaskStatus.Running) {
490 if (childTasks == null || childTasks.IsSet)
491 status = TaskStatus.RanToCompletion;
493 status = TaskStatus.WaitingForChildrenToComplete;
496 if (status != TaskStatus.WaitingForChildrenToComplete)
497 ProcessCompleteDelegates ();
499 // Reset the current thingies
501 TaskScheduler.Current = null;
503 if (cancelation_registration.HasValue)
504 cancelation_registration.Value.Dispose ();
506 // Tell parent that we are finished
507 if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
508 parent.ChildCompleted (this.Exception);
512 void CompletionExecutor (Task cont)
514 if (cont.Slot.Predicate != null && !cont.Slot.Predicate ())
517 if (!cont.Slot.Launched.TryRelaxedSet ())
520 if (!ContinuationStatusCheck (cont.Slot.Kind)) {
527 if ((cont.Slot.Kind & TaskContinuationOptions.ExecuteSynchronously) != 0)
528 cont.RunSynchronously (cont.scheduler);
533 void ProcessCompleteDelegates ()
535 if (!completed.HasElements)
539 while (completed.TryGetNextCompletion (out continuation))
540 CompletionExecutor (continuation);
543 void ProcessChildExceptions ()
545 if (childExceptions == null)
548 if (exception == null)
549 exception = new AggregateException ();
551 AggregateException childEx;
552 while (childExceptions.TryDequeue (out childEx))
553 exception.AddChildException (childEx);
557 #region Cancel and Wait related method
559 internal void CancelReal ()
561 status = TaskStatus.Canceled;
562 ProcessCompleteDelegates ();
565 internal void HandleGenericException (Exception e)
567 HandleGenericException (new AggregateException (e));
570 internal void HandleGenericException (AggregateException e)
573 Thread.MemoryBarrier ();
574 status = TaskStatus.Faulted;
575 if (scheduler != null && scheduler.FireUnobservedEvent (exception).Observed)
576 exceptionObserved = true;
581 Wait (Timeout.Infinite, CancellationToken.None);
584 public void Wait (CancellationToken cancellationToken)
586 Wait (Timeout.Infinite, cancellationToken);
589 public bool Wait (TimeSpan timeout)
591 return Wait (CheckTimeout (timeout), CancellationToken.None);
594 public bool Wait (int millisecondsTimeout)
596 return Wait (millisecondsTimeout, CancellationToken.None);
599 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
601 if (millisecondsTimeout < -1)
602 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
604 bool result = IsCompleted;
606 if (scheduler == null) {
607 Watch watch = Watch.StartNew ();
609 schedWait.Wait (millisecondsTimeout, cancellationToken);
610 millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
613 var wait_event = new ManualResetEventSlim (false);
614 CancellationTokenRegistration? registration = null;
617 if (cancellationToken.CanBeCanceled) {
618 registration = cancellationToken.Register (wait_event.Set);
621 // FIXME: The implementation is wrong and slow
622 // It adds a continuation to the task which is then
623 // returned to parent causing all sort of problems when
624 // timeout is reached before task is finished
625 result = !scheduler.ParticipateUntil (this, wait_event, millisecondsTimeout);
627 if (registration.HasValue)
628 registration.Value.Dispose ();
633 throw new AggregateException (new TaskCanceledException (this));
635 if (exception != null)
641 public static void WaitAll (params Task[] tasks)
643 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
646 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
648 WaitAll (tasks, Timeout.Infinite, cancellationToken);
651 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
653 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
656 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
658 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
661 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
664 throw new ArgumentNullException ("tasks");
667 bool simple_run = millisecondsTimeout == Timeout.Infinite || tasks.Length == 1;
668 List<Exception> exceptions = null;
670 foreach (var t in tasks) {
672 throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
676 result &= t.Wait (millisecondsTimeout, cancellationToken);
677 } catch (AggregateException e) {
678 if (exceptions == null)
679 exceptions = new List<Exception> ();
681 exceptions.AddRange (e.InnerExceptions);
686 // FIXME: Wrong implementation, millisecondsTimeout is total time not time per task
688 foreach (var t in tasks) {
690 result &= t.Wait (millisecondsTimeout, cancellationToken);
691 } catch (AggregateException e) {
692 if (exceptions == null)
693 exceptions = new List<Exception> ();
695 exceptions.AddRange (e.InnerExceptions);
700 if (exceptions != null)
701 throw new AggregateException (exceptions);
706 public static int WaitAny (params Task[] tasks)
708 return WaitAny (tasks, -1, CancellationToken.None);
711 public static int WaitAny (Task[] tasks, TimeSpan timeout)
713 return WaitAny (tasks, CheckTimeout (timeout));
716 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
718 if (millisecondsTimeout < -1)
719 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
721 if (millisecondsTimeout == -1)
722 return WaitAny (tasks);
724 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
727 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
729 return WaitAny (tasks, -1, cancellationToken);
732 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
735 throw new ArgumentNullException ("tasks");
736 if (tasks.Length == 0)
737 throw new ArgumentException ("tasks is empty", "tasks");
738 if (tasks.Length == 1) {
739 tasks[0].Wait (millisecondsTimeout, cancellationToken);
744 int indexFirstFinished = -1;
746 TaskScheduler sched = null;
748 Watch watch = Watch.StartNew ();
749 ManualResetEventSlim predicateEvt = new ManualResetEventSlim (false);
751 foreach (Task t in tasks) {
752 int indexResult = index++;
753 t.ContinueWith (delegate {
754 if (numFinished >= 1)
756 int result = Interlocked.Increment (ref numFinished);
758 // Check if we are the first to have finished
760 indexFirstFinished = indexResult;
764 }, TaskContinuationOptions.ExecuteSynchronously);
766 if (sched == null && t.scheduler != null) {
772 // If none of task have a scheduler we are forced to wait for at least one to start
774 var handles = Array.ConvertAll (tasks, t => t.schedWait.WaitHandle);
776 if ((shandle = WaitHandle.WaitAny (handles, millisecondsTimeout)) == WaitHandle.WaitTimeout)
778 sched = tasks[shandle].scheduler;
779 task = tasks[shandle];
780 millisecondsTimeout = ComputeTimeout (millisecondsTimeout, watch);
783 // One task already finished
784 if (indexFirstFinished != -1)
785 return indexFirstFinished;
787 if (cancellationToken != CancellationToken.None) {
788 cancellationToken.Register (predicateEvt.Set);
789 cancellationToken.ThrowIfCancellationRequested ();
792 sched.ParticipateUntil (task, predicateEvt, millisecondsTimeout);
794 // Index update is still not done
795 if (indexFirstFinished == -1) {
796 SpinWait wait = new SpinWait ();
797 while (indexFirstFinished == -1)
801 return indexFirstFinished;
804 static int CheckTimeout (TimeSpan timeout)
807 return checked ((int)timeout.TotalMilliseconds);
808 } catch (System.OverflowException) {
809 throw new ArgumentOutOfRangeException ("timeout");
813 static int ComputeTimeout (int millisecondsTimeout, Watch watch)
815 return millisecondsTimeout == -1 ? -1 : (int)Math.Max (watch.ElapsedMilliseconds - millisecondsTimeout, 1);
821 public void Dispose ()
826 protected virtual void Dispose (bool disposing)
829 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
831 // Set action to null so that the GC can collect the delegate and thus
832 // any big object references that the user might have captured in a anonymous method
842 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
844 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
847 public Task ContinueWith (Action<Task, object> continuationAction, object state)
849 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
852 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
854 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
857 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
859 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
862 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
864 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
867 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
868 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
870 if (continuationAction == null)
871 throw new ArgumentNullException ("continuationAction");
872 if (scheduler == null)
873 throw new ArgumentNullException ("scheduler");
875 Task continuation = new Task (l => continuationAction (this, l), state,
877 GetCreationOptions (continuationOptions),
879 ContinueWithCore (continuation, continuationOptions, scheduler);
884 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
886 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
889 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
891 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
894 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
896 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
899 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
901 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
904 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
905 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
907 if (continuationFunction == null)
908 throw new ArgumentNullException ("continuationFunction");
909 if (scheduler == null)
910 throw new ArgumentNullException ("scheduler");
912 var t = new Task<TResult> (l => continuationFunction (this, l),
915 GetCreationOptions (continuationOptions),
918 ContinueWithCore (t, continuationOptions, scheduler);
923 public static Task<TResult> FromResult<TResult> (TResult result)
925 var tcs = new TaskCompletionSource<TResult> ();
926 tcs.SetResult (result);
930 public TaskAwaiter GetAwaiter ()
932 return new TaskAwaiter (this);
935 public static Task Run (Action action)
937 return Run (action, CancellationToken.None);
940 public static Task Run (Action action, CancellationToken cancellationToken)
942 if (cancellationToken.IsCancellationRequested)
943 return TaskConstants.Canceled;
945 var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
950 public static Task Run (Func<Task> function)
952 return Run (function, CancellationToken.None);
955 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
957 if (cancellationToken.IsCancellationRequested)
958 return TaskConstants.Canceled;
960 var t = new Task<Task> (function, cancellationToken);
965 public static Task<TResult> Run<TResult> (Func<TResult> function)
967 return Run (function, CancellationToken.None);
970 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
972 if (cancellationToken.IsCancellationRequested)
973 return TaskConstants<TResult>.Canceled;
975 var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
980 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
982 return Run (function, CancellationToken.None);
985 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
987 if (cancellationToken.IsCancellationRequested)
988 return TaskConstants<TResult>.Canceled;
990 var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
991 return GetTaskResult (t);
994 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
996 var r = await task.ConfigureAwait (false);
1000 public static YieldAwaitable Yield ()
1002 return new YieldAwaitable ();
1007 public static TaskFactory Factory {
1009 return defaultFactory;
1013 public static int? CurrentId {
1016 return t == null ? (int?)null : t.Id;
1020 public AggregateException Exception {
1022 exceptionObserved = true;
1031 public bool IsCanceled {
1033 return status == TaskStatus.Canceled;
1037 public bool IsCompleted {
1039 return status == TaskStatus.RanToCompletion ||
1040 status == TaskStatus.Canceled || status == TaskStatus.Faulted;
1044 public bool IsFaulted {
1046 return status == TaskStatus.Faulted;
1050 public TaskCreationOptions CreationOptions {
1052 return taskCreationOptions;
1056 public TaskStatus Status {
1065 public object AsyncState {
1071 bool IAsyncResult.CompletedSynchronously {
1077 WaitHandle IAsyncResult.AsyncWaitHandle {
1089 internal Task Parent {
1095 internal string DisplayActionMethod {
1097 Delegate d = simpleAction ?? (Delegate) action;
1098 return d == null ? "<none>" : d.Method.ToString ();