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 (HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
154 && parent != null && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
156 if (HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
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");
209 SetupScheduler (scheduler);
210 var saveStatus = status;
211 Status = TaskStatus.WaitingToRun;
214 if (scheduler.RunInline (this, false))
216 } catch (Exception inner) {
217 throw new TaskSchedulerException (inner);
227 public Task ContinueWith (Action<Task> continuationAction)
229 return ContinueWith (continuationAction, TaskContinuationOptions.None);
232 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
234 return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
237 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
239 return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
242 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
244 return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
247 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
249 if (continuationAction == null)
250 throw new ArgumentNullException ("continuationAction");
251 if (scheduler == null)
252 throw new ArgumentNullException ("scheduler");
254 return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
257 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
259 var lazyCancellation = false;
261 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
263 var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
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 return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
300 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
302 var lazyCancellation = false;
304 lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
306 var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
307 ContinueWithCore (continuation, continuationOptions, scheduler);
312 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
314 const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
315 const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
316 const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
318 if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
319 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
321 // Already set the scheduler so that user can call Wait and that sort of stuff
322 continuation.scheduler = scheduler;
323 continuation.Status = TaskStatus.WaitingForActivation;
325 ContinueWith (new TaskContinuation (continuation, options));
328 internal void ContinueWith (IContinuation continuation)
331 continuation.Execute ();
335 continuations.Add (continuation);
337 // Retry in case completion was achieved but event adding was too late
338 if (IsCompleted && continuations.Remove (continuation))
339 continuation.Execute ();
342 void RemoveContinuation (IContinuation continuation)
344 continuations.Remove (continuation);
347 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
349 TaskCreationOptions options = TaskCreationOptions.None;
350 if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
351 options |= TaskCreationOptions.AttachedToParent;
352 if ((kind & TaskContinuationOptions.PreferFairness) > 0)
353 options |= TaskCreationOptions.PreferFairness;
354 if ((kind & TaskContinuationOptions.LongRunning) > 0)
355 options |= TaskCreationOptions.LongRunning;
361 #region Internal and protected thingies
362 internal void Schedule ()
364 Status = TaskStatus.WaitingToRun;
366 // If worker is null it means it is a local one, revert to the old behavior
367 // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
368 if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
369 scheduler.QueueTask (this);
371 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
372 * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
373 * the correct Thread during the creation
375 childWorkAdder (this);
381 /* Allow scheduler to break fairness of deque ordering without
382 * breaking its semantic (the task can be executed twice but the
383 * second time it will return immediately
385 if (!executing.TryRelaxedSet ())
388 // Disable CancellationToken direct cancellation
389 if (cancellationRegistration != null) {
390 cancellationRegistration.Value.Dispose ();
391 cancellationRegistration = null;
394 // If Task are ran inline on the same thread we might trash these values
395 var saveCurrent = current;
396 var saveScheduler = TaskScheduler.Current;
400 TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
402 TaskScheduler.Current = scheduler;
405 if (!token.IsCancellationRequested) {
407 status = TaskStatus.Running;
411 } catch (OperationCanceledException oce) {
412 if (token != CancellationToken.None && oce.CancellationToken == token)
415 HandleGenericException (oce);
416 } catch (Exception e) {
417 HandleGenericException (e);
423 if (saveCurrent != null)
424 current = saveCurrent;
425 if (saveScheduler != null)
426 TaskScheduler.Current = saveScheduler;
430 internal bool TrySetCanceled ()
435 if (!executing.TryRelaxedSet ()) {
436 var sw = new SpinWait ();
447 internal bool TrySetException (AggregateException aggregate)
452 if (!executing.TryRelaxedSet ()) {
453 var sw = new SpinWait ();
460 HandleGenericException (aggregate);
464 internal void Execute ()
469 internal void AddChild ()
471 if (childTasks == null)
472 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
473 childTasks.AddCount ();
476 internal void ChildCompleted (AggregateException childEx)
478 if (childEx != null) {
479 if (ExceptionSlot.ChildExceptions == null)
480 Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
481 ExceptionSlot.ChildExceptions.Enqueue (childEx);
484 if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
485 ProcessChildExceptions ();
486 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
487 ProcessCompleteDelegates ();
488 if (HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
489 parent.ChildCompleted (this.Exception);
495 if (IsContinuation) {
496 invoker.Invoke (contAncestor, state, this);
498 invoker.Invoke (this, state, this);
502 internal void Finish ()
504 // If there was children created and they all finished, we set the countdown
505 if (childTasks != null) {
506 if (childTasks.Signal ())
507 ProcessChildExceptions (true);
510 // Don't override Canceled or Faulted
511 if (status == TaskStatus.Running) {
512 if (childTasks == null || childTasks.IsSet)
513 Status = TaskStatus.RanToCompletion;
515 Status = TaskStatus.WaitingForChildrenToComplete;
518 // Completions are already processed when task is canceled or faulted
519 if (status == TaskStatus.RanToCompletion)
520 ProcessCompleteDelegates ();
522 // Reset the current thingies
525 if (TaskScheduler.Current == scheduler)
526 TaskScheduler.Current = null;
528 if (cancellationRegistration.HasValue)
529 cancellationRegistration.Value.Dispose ();
531 // Tell parent that we are finished
532 if (HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) && parent != null && status != TaskStatus.WaitingForChildrenToComplete) {
533 parent.ChildCompleted (this.Exception);
537 void ProcessCompleteDelegates ()
539 if (continuations.HasElements) {
540 IContinuation continuation;
541 while (continuations.TryGetNextCompletion (out continuation))
542 continuation.Execute ();
546 void ProcessChildExceptions (bool isParent = false)
548 if (exSlot == null || exSlot.ChildExceptions == null)
551 if (ExceptionSlot.Exception == null)
552 exSlot.Exception = new AggregateException ();
554 AggregateException childEx;
555 while (exSlot.ChildExceptions.TryDequeue (out childEx))
556 exSlot.Exception.AddChildException (childEx);
559 Status = TaskStatus.Faulted;
560 ProcessCompleteDelegates ();
565 #region Cancel and Wait related method
567 internal void CancelReal ()
569 Status = TaskStatus.Canceled;
570 ProcessCompleteDelegates ();
573 void HandleGenericException (Exception e)
575 HandleGenericException (new AggregateException (e));
578 void HandleGenericException (AggregateException e)
580 ExceptionSlot.Exception = e;
581 Thread.MemoryBarrier ();
582 Status = TaskStatus.Faulted;
583 ProcessCompleteDelegates ();
586 internal bool WaitOnChildren ()
588 if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
597 Wait (Timeout.Infinite, CancellationToken.None);
600 public void Wait (CancellationToken cancellationToken)
602 Wait (Timeout.Infinite, cancellationToken);
605 public bool Wait (TimeSpan timeout)
607 return Wait (CheckTimeout (timeout), CancellationToken.None);
610 public bool Wait (int millisecondsTimeout)
612 return Wait (millisecondsTimeout, CancellationToken.None);
615 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
617 if (millisecondsTimeout < -1)
618 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
623 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
624 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
625 scheduler.RunInline (this, true);
628 var continuation = new ManualResetContinuation ();
630 ContinueWith (continuation);
631 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
634 RemoveContinuation (continuation);
635 continuation.Dispose ();
641 throw new AggregateException (new TaskCanceledException (this));
643 var exception = Exception;
644 if (exception != null)
647 if (childTasks != null)
653 public static void WaitAll (params Task[] tasks)
655 WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
658 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
660 WaitAll (tasks, Timeout.Infinite, cancellationToken);
663 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
665 return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
668 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
670 return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
673 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
676 throw new ArgumentNullException ("tasks");
679 foreach (var t in tasks) {
681 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
683 result &= t.Status == TaskStatus.RanToCompletion;
687 var continuation = new CountdownContinuation (tasks.Length);
689 foreach (var t in tasks)
690 t.ContinueWith (continuation);
692 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
694 List<Exception> exceptions = null;
696 foreach (var t in tasks) {
698 if (t.Status == TaskStatus.RanToCompletion)
700 if (exceptions == null)
701 exceptions = new List<Exception> ();
702 if (t.Exception != null)
703 exceptions.AddRange (t.Exception.InnerExceptions);
705 exceptions.Add (new TaskCanceledException (t));
707 t.RemoveContinuation (continuation);
711 continuation.Dispose ();
713 if (exceptions != null)
714 throw new AggregateException (exceptions);
721 public static int WaitAny (params Task[] tasks)
723 return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
726 public static int WaitAny (Task[] tasks, TimeSpan timeout)
728 return WaitAny (tasks, CheckTimeout (timeout));
731 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
733 return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
736 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
738 return WaitAny (tasks, Timeout.Infinite, cancellationToken);
741 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
744 throw new ArgumentNullException ("tasks");
745 if (millisecondsTimeout < -1)
746 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
747 CheckForNullTasks (tasks);
749 if (tasks.Length > 0) {
750 var continuation = new ManualResetContinuation ();
753 for (int i = 0; i < tasks.Length; i++) {
757 t.ContinueWith (continuation);
760 if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
764 foreach (var t in tasks)
765 t.RemoveContinuation (continuation);
766 continuation.Dispose ();
770 int firstFinished = -1;
771 for (int i = 0; i < tasks.Length; i++) {
779 return firstFinished;
782 static int CheckTimeout (TimeSpan timeout)
785 return checked ((int)timeout.TotalMilliseconds);
786 } catch (System.OverflowException) {
787 throw new ArgumentOutOfRangeException ("timeout");
791 static void CheckForNullTasks (Task[] tasks)
793 foreach (var t in tasks)
795 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
800 public void Dispose ()
805 protected virtual void Dispose (bool disposing)
808 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
810 // Set action to null so that the GC can collect the delegate and thus
811 // any big object references that the user might have captured in a anonymous method
815 if (cancellationRegistration != null)
816 cancellationRegistration.Value.Dispose ();
823 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
825 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
828 public Task ContinueWith (Action<Task, object> continuationAction, object state)
830 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
833 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
835 return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
838 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
840 return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
843 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
845 return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
848 public 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);
866 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
868 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
871 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
873 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
876 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
878 return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
881 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
883 return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
886 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
887 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
889 if (continuationFunction == null)
890 throw new ArgumentNullException ("continuationFunction");
891 if (scheduler == null)
892 throw new ArgumentNullException ("scheduler");
894 var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
897 GetCreationOptions (continuationOptions),
901 ContinueWithCore (t, continuationOptions, scheduler);
906 public static Task Delay (int millisecondsDelay)
908 return Delay (millisecondsDelay, CancellationToken.None);
911 public static Task Delay (TimeSpan delay)
913 return Delay (CheckTimeout (delay), CancellationToken.None);
916 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
918 return Delay (CheckTimeout (delay), cancellationToken);
921 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
923 if (millisecondsDelay < -1)
924 throw new ArgumentOutOfRangeException ("millisecondsDelay");
926 var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
927 task.SetupScheduler (TaskScheduler.Current);
929 if (millisecondsDelay != Timeout.Infinite)
930 task.scheduler.QueueTask (task);
935 public static Task<TResult> FromResult<TResult> (TResult result)
937 var tcs = new TaskCompletionSource<TResult> ();
938 tcs.SetResult (result);
942 public TaskAwaiter GetAwaiter ()
944 return new TaskAwaiter (this);
947 public static Task Run (Action action)
949 return Run (action, CancellationToken.None);
952 public static Task Run (Action action, CancellationToken cancellationToken)
954 if (cancellationToken.IsCancellationRequested)
955 return TaskConstants.Canceled;
957 return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
960 public static Task Run (Func<Task> function)
962 return Run (function, CancellationToken.None);
965 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
967 if (cancellationToken.IsCancellationRequested)
968 return TaskConstants.Canceled;
970 return TaskExtensions.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
973 public static Task<TResult> Run<TResult> (Func<TResult> function)
975 return Run (function, CancellationToken.None);
978 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
980 if (cancellationToken.IsCancellationRequested)
981 return TaskConstants<TResult>.Canceled;
983 return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
986 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
988 return Run (function, CancellationToken.None);
991 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
993 if (cancellationToken.IsCancellationRequested)
994 return TaskConstants<TResult>.Canceled;
996 return TaskExtensions.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
999 public static Task WhenAll (params Task[] tasks)
1002 throw new ArgumentNullException ("tasks");
1004 return WhenAllCore (tasks);
1007 public static Task WhenAll (IEnumerable<Task> tasks)
1010 throw new ArgumentNullException ("tasks");
1012 // Call ToList on input enumeration or we end up
1013 // enumerating it more than once
1014 return WhenAllCore (new List<Task> (tasks));
1017 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1020 throw new ArgumentNullException ("tasks");
1022 return WhenAllCore<TResult> (tasks);
1025 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1028 throw new ArgumentNullException ("tasks");
1030 // Call ToList on input enumeration or we end up
1031 // enumerating it more than once
1032 return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1035 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1037 foreach (var t in tasks) {
1039 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1042 var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1043 task.SetupScheduler (TaskScheduler.Current);
1045 var continuation = new WhenAllContinuation<TResult> (task, tasks);
1046 foreach (var t in tasks)
1047 t.ContinueWith (continuation);
1052 public static Task<Task> WhenAny (params Task[] tasks)
1055 throw new ArgumentNullException ("tasks");
1057 return WhenAnyCore (tasks);
1060 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1063 throw new ArgumentNullException ("tasks");
1065 return WhenAnyCore (new List<Task> (tasks));
1068 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1071 throw new ArgumentNullException ("tasks");
1073 return WhenAnyCore<TResult> (tasks);
1076 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1079 throw new ArgumentNullException ("tasks");
1081 return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1084 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1086 if (tasks.Count == 0)
1087 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1089 int completed_index = -1;
1090 for (int i = 0; i < tasks.Count; ++i) {
1093 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1095 if (t.IsCompleted && completed_index < 0)
1096 completed_index = i;
1099 var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1101 if (completed_index > 0) {
1102 task.TrySetResult (tasks[completed_index]);
1106 task.SetupScheduler (TaskScheduler.Current);
1108 var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1109 foreach (var t in tasks)
1110 t.ContinueWith (continuation);
1115 public static YieldAwaitable Yield ()
1117 return new YieldAwaitable ();
1121 internal static Task WhenAllCore (IList<Task> tasks)
1123 bool all_completed = true;
1124 foreach (var t in tasks) {
1126 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1128 all_completed &= t.Status == TaskStatus.RanToCompletion;
1132 return TaskConstants.Finished;
1134 var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1135 task.SetupScheduler (TaskScheduler.Current);
1137 var continuation = new WhenAllContinuation (task, tasks);
1138 foreach (var t in tasks)
1139 t.ContinueWith (continuation);
1144 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1146 if (tasks.Count == 0)
1147 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1149 int completed_index = -1;
1150 for (int i = 0; i < tasks.Count; ++i) {
1153 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1155 if (t.IsCompleted && completed_index < 0)
1156 completed_index = i;
1159 var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1161 if (completed_index > 0) {
1162 task.TrySetResult (tasks[completed_index]);
1166 task.SetupScheduler (TaskScheduler.Current);
1168 var continuation = new WhenAnyContinuation<Task> (task, tasks);
1169 foreach (var t in tasks)
1170 t.ContinueWith (continuation);
1176 internal CancellationToken CancellationToken {
1182 public static TaskFactory Factory {
1184 return defaultFactory;
1188 public static int? CurrentId {
1191 return t == null ? (int?)null : t.Id;
1195 public AggregateException Exception {
1199 exSlot.Observed = true;
1200 return exSlot.Exception;
1204 public bool IsCanceled {
1206 return status == TaskStatus.Canceled;
1210 public bool IsCompleted {
1212 return status >= TaskStatus.RanToCompletion;
1216 public bool IsFaulted {
1218 return status == TaskStatus.Faulted;
1222 public TaskCreationOptions CreationOptions {
1224 return creationOptions & MaxTaskCreationOptions;
1228 public TaskStatus Status {
1234 Thread.MemoryBarrier ();
1238 TaskExceptionSlot ExceptionSlot {
1242 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1247 public object AsyncState {
1253 bool IAsyncResult.CompletedSynchronously {
1259 WaitHandle IAsyncResult.AsyncWaitHandle {
1271 bool IsContinuation {
1273 return contAncestor != null;
1277 internal Task ContinuationAncestor {
1279 return contAncestor;
1283 internal string DisplayActionMethod {
1285 Delegate d = invoker.Action;
1286 return d == null ? "<none>" : d.Method.ToString ();