5 // Marek Safar <marek.safar@gmail.com>
6 // Jérémie Laval <jeremie dot laval at xamarin dot com>
8 // Copyright (c) 2008 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34 using System.Threading;
35 using System.Collections.Concurrent;
36 using System.Collections.Generic;
37 using System.Runtime.CompilerServices;
39 namespace System.Threading.Tasks
41 [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
42 [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
43 public class Task : IDisposable, IAsyncResult
45 // With this attribute each thread has its own value so that it's correct for our Schedule code
46 // and for Parent property.
50 static Action<Task> childWorkAdder;
52 // parent is the outer task in which this task is created
54 // contAncestor is the Task on which this continuation was setup
55 readonly Task contAncestor;
58 static readonly TaskFactory defaultFactory = new TaskFactory ();
60 CountdownEvent childTasks;
63 TaskCreationOptions creationOptions;
65 internal TaskScheduler scheduler;
67 TaskExceptionSlot exSlot;
71 TaskActionInvoker invoker;
73 internal AtomicBooleanValue executing;
75 TaskCompletionQueue<IContinuation> continuations;
77 CancellationToken token;
78 CancellationTokenRegistration? cancellationRegistration;
80 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
82 const TaskCreationOptions MaxTaskCreationOptions =
84 TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
86 TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
88 public Task (Action action)
89 : this (action, TaskCreationOptions.None)
94 public Task (Action action, TaskCreationOptions creationOptions)
95 : this (action, CancellationToken.None, creationOptions)
100 public Task (Action action, CancellationToken cancellationToken)
101 : this (action, cancellationToken, TaskCreationOptions.None)
106 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107 : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
110 throw new ArgumentNullException ("action");
111 if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
112 throw new ArgumentOutOfRangeException ("creationOptions");
115 public Task (Action<object> action, object state)
116 : 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 (TaskActionInvoker.Create (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 (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
140 TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
142 this.invoker = invoker;
143 this.creationOptions = creationOptions;
145 this.taskId = Interlocked.Increment (ref id);
146 this.token = cancellationToken;
147 this.parent = parent = parent == null ? current : parent;
148 this.contAncestor = contAncestor;
149 this.status = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
151 // Process creationOptions
153 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
154 && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
156 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
160 if (token.CanBeCanceled && !ignoreCancellation)
161 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
164 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
166 return (opt & member) == member;
172 Start (TaskScheduler.Current);
175 public void Start (TaskScheduler scheduler)
177 if (scheduler == null)
178 throw new ArgumentNullException ("scheduler");
180 if (status >= TaskStatus.WaitingToRun)
181 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
184 throw new InvalidOperationException ("Start may not be called on a continuation task");
186 SetupScheduler (scheduler);
190 internal void SetupScheduler (TaskScheduler scheduler)
192 this.scheduler = scheduler;
193 Status = TaskStatus.WaitingForActivation;
196 public void RunSynchronously ()
198 RunSynchronously (TaskScheduler.Current);
201 public void RunSynchronously (TaskScheduler scheduler)
203 if (scheduler == null)
204 throw new ArgumentNullException ("scheduler");
206 if (Status > TaskStatus.WaitingForActivation)
207 throw new InvalidOperationException ("The task is not in a valid state to be started");
210 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
212 RunSynchronouslyCore (scheduler);
215 internal void RunSynchronouslyCore (TaskScheduler scheduler)
217 SetupScheduler (scheduler);
218 var saveStatus = status;
219 Status = TaskStatus.WaitingToRun;
222 if (scheduler.RunInline (this, false))
224 } catch (Exception inner) {
225 throw new TaskSchedulerException (inner);
235 public Task ContinueWith (Action<Task> continuationAction)
237 return ContinueWith (continuationAction, TaskContinuationOptions.None);
240 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
242 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
245 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
247 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
250 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
252 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
255 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
257 if (continuationAction == null)
258 throw new ArgumentNullException ("continuationAction");
259 if (scheduler == null)
260 throw new ArgumentNullException ("scheduler");
262 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
265 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
267 var lazyCancellation = false;
269 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
271 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
272 ContinueWithCore (continuation, continuationOptions, scheduler);
277 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
279 return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
282 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
284 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
287 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
289 return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
292 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
294 return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
297 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
298 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
300 if (continuationFunction == null)
301 throw new ArgumentNullException ("continuationFunction");
302 if (scheduler == null)
303 throw new ArgumentNullException ("scheduler");
305 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
308 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
310 var lazyCancellation = false;
312 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
314 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
315 ContinueWithCore (continuation, continuationOptions, scheduler);
320 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
322 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
323 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
324 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
326 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
327 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
329 // Already set the scheduler so that user can call Wait and that sort of stuff
330 continuation.scheduler = scheduler;
331 continuation.Status = TaskStatus.WaitingForActivation;
333 ContinueWith (new TaskContinuation (continuation, options));
336 internal void ContinueWith (IContinuation continuation)
339 continuation.Execute ();
343 continuations.Add (continuation);
345 // Retry in case completion was achieved but event adding was too late
346 if (IsCompleted && continuations.Remove (continuation))
347 continuation.Execute ();
350 internal void RemoveContinuation (IContinuation continuation)
352 continuations.Remove (continuation);
355 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
357 TaskCreationOptions options = TaskCreationOptions.None;
358 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
359 options |= TaskCreationOptions.AttachedToParent;
360 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
361 options |= TaskCreationOptions.PreferFairness;
362 if ((kind & TaskContinuationOptions.LongRunning) > 0)
363 options |= TaskCreationOptions.LongRunning;
369 #region Internal and protected thingies
370 internal void Schedule ()
372 Status = TaskStatus.WaitingToRun;
374 // If worker is null it means it is a local one, revert to the old behavior
375 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
376 if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
377 scheduler.QueueTask (this);
379 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
380 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
381 * the correct Thread during the creation
383 childWorkAdder (this);
389 /* Allow scheduler to break fairness of deque ordering without
390 * breaking its semantic (the task can be executed twice but the
391 * second time it will return immediately
393 if (!executing.TryRelaxedSet ())
396 // Disable CancellationToken direct cancellation
397 if (cancellationRegistration != null) {
398 cancellationRegistration.Value.Dispose ();
399 cancellationRegistration = null;
402 // If Task are ran inline on the same thread we might trash these values
403 var saveCurrent = current;
404 var saveScheduler = TaskScheduler.Current;
408 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
410 TaskScheduler.Current = scheduler;
413 if (!token.IsCancellationRequested) {
415 status = TaskStatus.Running;
419 } catch (OperationCanceledException oce) {
420 if (token != CancellationToken.None && oce.CancellationToken == token)
423 HandleGenericException (oce);
424 } catch (Exception e) {
425 HandleGenericException (e);
431 if (saveCurrent != null)
432 current = saveCurrent;
433 if (saveScheduler != null)
434 TaskScheduler.Current = saveScheduler;
438 internal bool TrySetCanceled ()
443 if (!executing.TryRelaxedSet ()) {
444 var sw = new SpinWait ();
455 internal bool TrySetException (AggregateException aggregate)
460 if (!executing.TryRelaxedSet ()) {
461 var sw = new SpinWait ();
468 HandleGenericException (aggregate);
472 internal bool TrySetExceptionObserved ()
474 if (exSlot != null) {
475 exSlot.Observed = true;
481 internal void Execute ()
486 internal void AddChild ()
488 if (childTasks == null)
489 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
490 childTasks.AddCount ();
493 internal void ChildCompleted (AggregateException childEx)
495 if (childEx != null) {
496 if (ExceptionSlot.ChildExceptions == null)
497 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
498 ExceptionSlot.ChildExceptions.Enqueue (childEx);
501 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
502 ProcessChildExceptions ();
503 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
504 ProcessCompleteDelegates ();
505 if (parent != null &&
507 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
509 HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
510 parent.ChildCompleted (this.Exception);
516 if (IsContinuation) {
517 invoker.Invoke (contAncestor, state, this);
519 invoker.Invoke (this, state, this);
523 internal void Finish ()
525 // If there was children created and they all finished, we set the countdown
526 if (childTasks != null) {
527 if (childTasks.Signal ())
528 ProcessChildExceptions (true);
531 // Don't override Canceled or Faulted
532 if (status == TaskStatus.Running) {
533 if (childTasks == null || childTasks.IsSet)
534 Status = TaskStatus.RanToCompletion;
536 Status = TaskStatus.WaitingForChildrenToComplete;
539 // Tell parent that we are finished
540 if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
542 !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
544 status != TaskStatus.WaitingForChildrenToComplete) {
545 parent.ChildCompleted (this.Exception);
548 // Completions are already processed when task is canceled or faulted
549 if (status == TaskStatus.RanToCompletion)
550 ProcessCompleteDelegates ();
552 // Reset the current thingies
555 if (TaskScheduler.Current == scheduler)
556 TaskScheduler.Current = null;
558 if (cancellationRegistration.HasValue)
559 cancellationRegistration.Value.Dispose ();
562 void ProcessCompleteDelegates ()
564 if (continuations.HasElements) {
565 IContinuation continuation;
566 while (continuations.TryGetNextCompletion (out continuation))
567 continuation.Execute ();
571 void ProcessChildExceptions (bool isParent = false)
573 if (exSlot == null || exSlot.ChildExceptions == null)
576 if (ExceptionSlot.Exception == null)
577 exSlot.Exception = new AggregateException ();
579 AggregateException childEx;
580 while (exSlot.ChildExceptions.TryDequeue (out childEx))
581 exSlot.Exception.AddChildException (childEx);
584 Status = TaskStatus.Faulted;
585 ProcessCompleteDelegates ();
590 #region Cancel and Wait related method
592 internal void CancelReal ()
594 Status = TaskStatus.Canceled;
595 ProcessCompleteDelegates ();
598 void HandleGenericException (Exception e)
600 HandleGenericException (new AggregateException (e));
603 void HandleGenericException (AggregateException e)
605 ExceptionSlot.Exception = e;
606 Thread.MemoryBarrier ();
607 Status = TaskStatus.Faulted;
608 ProcessCompleteDelegates ();
611 internal bool WaitOnChildren ()
613 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
622 Wait (Timeout.Infinite, CancellationToken.None);
625 public void Wait (CancellationToken cancellationToken)
627 Wait (Timeout.Infinite, cancellationToken);
630 public bool Wait (TimeSpan timeout)
632 return Wait (CheckTimeout (timeout), CancellationToken.None);
635 public bool Wait (int millisecondsTimeout)
637 return Wait (millisecondsTimeout, CancellationToken.None);
640 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
642 if (millisecondsTimeout < -1)
643 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
648 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
649 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
650 scheduler.RunInline (this, true);
653 var continuation = new ManualResetContinuation ();
655 ContinueWith (continuation);
656 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
659 RemoveContinuation (continuation);
660 continuation.Dispose ();
666 throw new AggregateException (new TaskCanceledException (this));
668 var exception = Exception;
669 if (exception != null)
675 public static void WaitAll (params Task[] tasks)
677 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
680 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
682 WaitAll (tasks, Timeout.Infinite, cancellationToken);
685 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
687 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
690 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
692 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
695 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
698 throw new ArgumentNullException ("tasks");
701 foreach (var t in tasks) {
703 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
705 result &= t.Status == TaskStatus.RanToCompletion;
709 var continuation = new CountdownContinuation (tasks.Length);
711 foreach (var t in tasks)
712 t.ContinueWith (continuation);
714 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
716 List<Exception> exceptions = null;
718 foreach (var t in tasks) {
720 if (t.Status == TaskStatus.RanToCompletion)
722 if (exceptions == null)
723 exceptions = new List<Exception> ();
724 if (t.Exception != null)
725 exceptions.AddRange (t.Exception.InnerExceptions);
727 exceptions.Add (new TaskCanceledException (t));
729 t.RemoveContinuation (continuation);
733 continuation.Dispose ();
735 if (exceptions != null)
736 throw new AggregateException (exceptions);
743 public static int WaitAny (params Task[] tasks)
745 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
748 public static int WaitAny (Task[] tasks, TimeSpan timeout)
750 return WaitAny (tasks, CheckTimeout (timeout));
753 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
755 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
758 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
760 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
763 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
766 throw new ArgumentNullException ("tasks");
767 if (millisecondsTimeout < -1)
768 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
769 CheckForNullTasks (tasks);
771 if (tasks.Length > 0) {
772 var continuation = new ManualResetContinuation ();
775 for (int i = 0; i < tasks.Length; i++) {
779 t.ContinueWith (continuation);
782 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
786 foreach (var t in tasks)
787 t.RemoveContinuation (continuation);
788 continuation.Dispose ();
792 int firstFinished = -1;
793 for (int i = 0; i < tasks.Length; i++) {
801 return firstFinished;
804 static int CheckTimeout (TimeSpan timeout)
807 return checked ((int)timeout.TotalMilliseconds);
808 } catch (System.OverflowException) {
809 throw new ArgumentOutOfRangeException ("timeout");
813 static void CheckForNullTasks (Task[] tasks)
815 foreach (var t in tasks)
817 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
822 public void Dispose ()
827 protected virtual void Dispose (bool disposing)
830 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
832 // Set action to null so that the GC can collect the delegate and thus
833 // any big object references that the user might have captured in a anonymous method
837 if (cancellationRegistration != null)
838 cancellationRegistration.Value.Dispose ();
848 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
849 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
851 if (continuationAction == null)
852 throw new ArgumentNullException ("continuationAction");
853 if (scheduler == null)
854 throw new ArgumentNullException ("scheduler");
856 Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
857 state, cancellationToken,
858 GetCreationOptions (continuationOptions),
861 ContinueWithCore (continuation, continuationOptions, scheduler);
868 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
870 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
873 public Task ContinueWith (Action<Task, object> continuationAction, object state)
875 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
878 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
880 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
883 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
885 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
888 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
890 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
893 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
895 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
898 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
900 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
903 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
905 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
908 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
910 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
913 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
914 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
916 if (continuationFunction == null)
917 throw new ArgumentNullException ("continuationFunction");
918 if (scheduler == null)
919 throw new ArgumentNullException ("scheduler");
921 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
924 GetCreationOptions (continuationOptions),
928 ContinueWithCore (t, continuationOptions, scheduler);
933 public static Task Delay (int millisecondsDelay)
935 return Delay (millisecondsDelay, CancellationToken.None);
938 public static Task Delay (TimeSpan delay)
940 return Delay (CheckTimeout (delay), CancellationToken.None);
943 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
945 return Delay (CheckTimeout (delay), cancellationToken);
948 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
950 if (millisecondsDelay < -1)
951 throw new ArgumentOutOfRangeException ("millisecondsDelay");
953 var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
954 task.SetupScheduler (TaskScheduler.Current);
956 if (millisecondsDelay != Timeout.Infinite)
957 task.scheduler.QueueTask (task);
962 public static Task<TResult> FromResult<TResult> (TResult result)
964 var tcs = new TaskCompletionSource<TResult> ();
965 tcs.SetResult (result);
969 public TaskAwaiter GetAwaiter ()
971 return new TaskAwaiter (this);
974 public static Task Run (Action action)
976 return Run (action, CancellationToken.None);
979 public static Task Run (Action action, CancellationToken cancellationToken)
981 if (cancellationToken.IsCancellationRequested)
982 return TaskConstants.Canceled;
984 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
987 public static Task Run (Func<Task> function)
989 return Run (function, CancellationToken.None);
992 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
994 if (cancellationToken.IsCancellationRequested)
995 return TaskConstants.Canceled;
997 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1000 public static Task<TResult> Run<TResult> (Func<TResult> function)
1002 return Run (function, CancellationToken.None);
1005 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1007 if (cancellationToken.IsCancellationRequested)
1008 return TaskConstants<TResult>.Canceled;
1010 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1013 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1015 return Run (function, CancellationToken.None);
1018 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1020 if (cancellationToken.IsCancellationRequested)
1021 return TaskConstants<TResult>.Canceled;
1023 return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1026 public static Task WhenAll (params Task[] tasks)
1029 throw new ArgumentNullException ("tasks");
1031 return WhenAllCore (tasks);
1034 public static Task WhenAll (IEnumerable<Task> tasks)
1037 throw new ArgumentNullException ("tasks");
1039 // Call ToList on input enumeration or we end up
1040 // enumerating it more than once
1041 return WhenAllCore (new List<Task> (tasks));
1044 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1047 throw new ArgumentNullException ("tasks");
1049 return WhenAllCore<TResult> (tasks);
1052 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1055 throw new ArgumentNullException ("tasks");
1057 // Call ToList on input enumeration or we end up
1058 // enumerating it more than once
1059 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1062 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1064 foreach (var t in tasks) {
1066 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1069 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1070 task.SetupScheduler (TaskScheduler.Current);
1072 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1073 foreach (var t in tasks)
1074 t.ContinueWith (continuation);
1079 public static Task<Task> WhenAny (params Task[] tasks)
1082 throw new ArgumentNullException ("tasks");
1084 return WhenAnyCore (tasks);
1087 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1090 throw new ArgumentNullException ("tasks");
1092 return WhenAnyCore (new List<Task> (tasks));
1095 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1098 throw new ArgumentNullException ("tasks");
1100 return WhenAnyCore<TResult> (tasks);
1103 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1106 throw new ArgumentNullException ("tasks");
1108 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1111 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1113 if (tasks.Count == 0)
1114 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1116 int completed_index = -1;
1117 for (int i = 0; i < tasks.Count; ++i) {
1120 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1122 if (t.IsCompleted && completed_index < 0)
1123 completed_index = i;
1126 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1128 if (completed_index > 0) {
1129 task.TrySetResult (tasks[completed_index]);
1133 task.SetupScheduler (TaskScheduler.Current);
1135 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1136 foreach (var t in tasks)
1137 t.ContinueWith (continuation);
1142 public static YieldAwaitable Yield ()
1144 return new YieldAwaitable ();
1148 internal static Task WhenAllCore (IList<Task> tasks)
1150 bool all_completed = true;
1151 foreach (var t in tasks) {
1153 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1155 all_completed &= t.Status == TaskStatus.RanToCompletion;
1159 return TaskConstants.Finished;
1161 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1162 task.SetupScheduler (TaskScheduler.Current);
1164 var continuation = new WhenAllContinuation (task, tasks);
1165 foreach (var t in tasks)
1166 t.ContinueWith (continuation);
1171 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1173 if (tasks.Count == 0)
1174 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1176 int completed_index = -1;
1177 for (int i = 0; i < tasks.Count; ++i) {
1180 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1182 if (t.IsCompleted && completed_index < 0)
1183 completed_index = i;
1186 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1188 if (completed_index > 0) {
1189 task.TrySetResult (tasks[completed_index]);
1193 task.SetupScheduler (TaskScheduler.Current);
1195 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1196 foreach (var t in tasks)
1197 t.ContinueWith (continuation);
1203 internal CancellationToken CancellationToken {
1209 public static TaskFactory Factory {
1211 return defaultFactory;
1215 public static int? CurrentId {
1218 return t == null ? (int?)null : t.Id;
1222 public AggregateException Exception {
1226 exSlot.Observed = true;
1227 return exSlot.Exception;
1231 public bool IsCanceled {
1233 return status == TaskStatus.Canceled;
1237 public bool IsCompleted {
1239 return status >= TaskStatus.RanToCompletion;
1243 public bool IsFaulted {
1245 return status == TaskStatus.Faulted;
1249 public TaskCreationOptions CreationOptions {
1251 return creationOptions & MaxTaskCreationOptions;
1255 public TaskStatus Status {
1261 Thread.MemoryBarrier ();
1265 TaskExceptionSlot ExceptionSlot {
1269 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1274 public object AsyncState {
1280 bool IAsyncResult.CompletedSynchronously {
1286 WaitHandle IAsyncResult.AsyncWaitHandle {
1298 bool IsContinuation {
1300 return contAncestor != null;
1304 internal Task ContinuationAncestor {
1306 return contAncestor;
1310 internal string DisplayActionMethod {
1312 Delegate d = invoker.Action;
1313 return d == null ? "<none>" : d.Method.ToString ();