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-2013 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 // parent is the outer task in which this task is created
52 // contAncestor is the Task on which this continuation was setup
53 readonly Task contAncestor
;
56 static readonly TaskFactory defaultFactory
= new TaskFactory ();
58 CountdownEvent childTasks
;
61 TaskCreationOptions creationOptions
;
63 internal TaskScheduler scheduler
;
65 TaskExceptionSlot exSlot
;
66 ManualResetEvent wait_handle
;
70 TaskActionInvoker invoker
;
72 internal AtomicBooleanValue executing
;
74 TaskCompletionQueue
<IContinuation
> continuations
;
76 CancellationToken token
;
77 CancellationTokenRegistration
? cancellationRegistration
;
79 internal const TaskCreationOptions WorkerTaskNotSupportedOptions
= TaskCreationOptions
.LongRunning
| TaskCreationOptions
.PreferFairness
;
81 const TaskCreationOptions MaxTaskCreationOptions
=
83 TaskCreationOptions
.DenyChildAttach
| TaskCreationOptions
.HideScheduler
|
85 TaskCreationOptions
.PreferFairness
| TaskCreationOptions
.LongRunning
| TaskCreationOptions
.AttachedToParent
;
87 public Task (Action action
)
88 : this (action
, TaskCreationOptions
.None
)
93 public Task (Action action
, TaskCreationOptions creationOptions
)
94 : this (action
, CancellationToken
.None
, creationOptions
)
99 public Task (Action action
, CancellationToken cancellationToken
)
100 : this (action
, cancellationToken
, TaskCreationOptions
.None
)
105 public Task (Action action
, CancellationToken cancellationToken
, TaskCreationOptions creationOptions
)
106 : this (TaskActionInvoker
.Create (action
), null, cancellationToken
, creationOptions
, current
)
109 throw new ArgumentNullException ("action");
110 if (creationOptions
> MaxTaskCreationOptions
|| creationOptions
< TaskCreationOptions
.None
)
111 throw new ArgumentOutOfRangeException ("creationOptions");
114 public Task (Action
<object> action
, object state
)
115 : this (action
, state
, TaskCreationOptions
.None
)
119 public Task (Action
<object> action
, object state
, TaskCreationOptions creationOptions
)
120 : this (action
, state
, CancellationToken
.None
, creationOptions
)
124 public Task (Action
<object> action
, object state
, CancellationToken cancellationToken
)
125 : this (action
, state
, cancellationToken
, TaskCreationOptions
.None
)
129 public Task (Action
<object> action
, object state
, CancellationToken cancellationToken
, TaskCreationOptions creationOptions
)
130 : this (TaskActionInvoker
.Create (action
), state
, cancellationToken
, creationOptions
, current
)
133 throw new ArgumentNullException ("action");
134 if (creationOptions
> MaxTaskCreationOptions
|| creationOptions
< TaskCreationOptions
.None
)
135 throw new ArgumentOutOfRangeException ("creationOptions");
138 internal Task (TaskActionInvoker invoker
, object state
, CancellationToken cancellationToken
,
139 TaskCreationOptions creationOptions
, Task parent
= null, Task contAncestor
= null, bool ignoreCancellation
= false)
141 this.invoker
= invoker
;
142 this.creationOptions
= creationOptions
;
144 this.taskId
= Interlocked
.Increment (ref id
);
145 this.token
= cancellationToken
;
146 this.parent
= parent
= parent
== null ? current
: parent
;
147 this.contAncestor
= contAncestor
;
148 this.status
= cancellationToken
.IsCancellationRequested
&& !ignoreCancellation
? TaskStatus
.Canceled
: TaskStatus
.Created
;
150 // Process creationOptions
152 if (parent
!= null && HasFlag (creationOptions
, TaskCreationOptions
.AttachedToParent
)
153 && !HasFlag (parent
.CreationOptions
, TaskCreationOptions
.DenyChildAttach
))
155 if (parent
!= null && HasFlag (creationOptions
, TaskCreationOptions
.AttachedToParent
))
159 if (token
.CanBeCanceled
&& !ignoreCancellation
)
160 cancellationRegistration
= token
.Register (l
=> ((Task
) l
).CancelReal (), this);
163 static bool HasFlag (TaskCreationOptions opt
, TaskCreationOptions member
)
165 return (opt
& member
) == member
;
171 Start (TaskScheduler
.Current
);
174 public void Start (TaskScheduler scheduler
)
176 if (scheduler
== null)
177 throw new ArgumentNullException ("scheduler");
179 if (status
>= TaskStatus
.WaitingToRun
)
180 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
183 throw new InvalidOperationException ("Start may not be called on a continuation task");
185 SetupScheduler (scheduler
);
189 internal void SetupScheduler (TaskScheduler scheduler
)
191 this.scheduler
= scheduler
;
192 Status
= TaskStatus
.WaitingForActivation
;
195 public void RunSynchronously ()
197 RunSynchronously (TaskScheduler
.Current
);
200 public void RunSynchronously (TaskScheduler scheduler
)
202 if (scheduler
== null)
203 throw new ArgumentNullException ("scheduler");
205 if (Status
> TaskStatus
.WaitingForActivation
)
206 throw new InvalidOperationException ("The task is not in a valid state to be started");
209 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
211 RunSynchronouslyCore (scheduler
);
214 internal void RunSynchronouslyCore (TaskScheduler scheduler
)
216 SetupScheduler (scheduler
);
217 var saveStatus
= status
;
218 Status
= TaskStatus
.WaitingToRun
;
221 if (scheduler
.RunInline (this, false))
223 } catch (Exception inner
) {
224 throw new TaskSchedulerException (inner
);
234 public Task
ContinueWith (Action
<Task
> continuationAction
)
236 return ContinueWith (continuationAction
, TaskContinuationOptions
.None
);
239 public Task
ContinueWith (Action
<Task
> continuationAction
, TaskContinuationOptions continuationOptions
)
241 return ContinueWith (continuationAction
, CancellationToken
.None
, continuationOptions
, TaskScheduler
.Current
);
244 public Task
ContinueWith (Action
<Task
> continuationAction
, CancellationToken cancellationToken
)
246 return ContinueWith (continuationAction
, cancellationToken
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
249 public Task
ContinueWith (Action
<Task
> continuationAction
, TaskScheduler scheduler
)
251 return ContinueWith (continuationAction
, CancellationToken
.None
, TaskContinuationOptions
.None
, scheduler
);
254 public Task
ContinueWith (Action
<Task
> continuationAction
, CancellationToken cancellationToken
, TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
256 if (continuationAction
== null)
257 throw new ArgumentNullException ("continuationAction");
258 if (scheduler
== null)
259 throw new ArgumentNullException ("scheduler");
261 return ContinueWith (TaskActionInvoker
.Create (continuationAction
), cancellationToken
, continuationOptions
, scheduler
);
264 internal Task
ContinueWith (TaskActionInvoker invoker
, CancellationToken cancellationToken
, TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
266 var lazyCancellation
= false;
268 lazyCancellation
= (continuationOptions
& TaskContinuationOptions
.LazyCancellation
) > 0;
270 var continuation
= new Task (invoker
, null, cancellationToken
, GetCreationOptions (continuationOptions
), null, this, lazyCancellation
);
271 ContinueWithCore (continuation
, continuationOptions
, scheduler
);
276 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, TResult
> continuationFunction
)
278 return ContinueWith
<TResult
> (continuationFunction
, TaskContinuationOptions
.None
);
281 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, TResult
> continuationFunction
, TaskContinuationOptions continuationOptions
)
283 return ContinueWith
<TResult
> (continuationFunction
, CancellationToken
.None
, continuationOptions
, TaskScheduler
.Current
);
286 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, TResult
> continuationFunction
, CancellationToken cancellationToken
)
288 return ContinueWith
<TResult
> (continuationFunction
, cancellationToken
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
291 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, TResult
> continuationFunction
, TaskScheduler scheduler
)
293 return ContinueWith
<TResult
> (continuationFunction
, CancellationToken
.None
, TaskContinuationOptions
.None
, scheduler
);
296 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, TResult
> continuationFunction
, CancellationToken cancellationToken
,
297 TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
299 if (continuationFunction
== null)
300 throw new ArgumentNullException ("continuationFunction");
301 if (scheduler
== null)
302 throw new ArgumentNullException ("scheduler");
304 return ContinueWith
<TResult
> (TaskActionInvoker
.Create (continuationFunction
), cancellationToken
, continuationOptions
, scheduler
);
307 internal Task
<TResult
> ContinueWith
<TResult
> (TaskActionInvoker invoker
, CancellationToken cancellationToken
, TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
309 var lazyCancellation
= false;
311 lazyCancellation
= (continuationOptions
& TaskContinuationOptions
.LazyCancellation
) > 0;
313 var continuation
= new Task
<TResult
> (invoker
, null, cancellationToken
, GetCreationOptions (continuationOptions
), parent
, this, lazyCancellation
);
314 ContinueWithCore (continuation
, continuationOptions
, scheduler
);
319 internal void ContinueWithCore (Task continuation
, TaskContinuationOptions options
, TaskScheduler scheduler
)
321 const TaskContinuationOptions wrongRan
= TaskContinuationOptions
.NotOnRanToCompletion
| TaskContinuationOptions
.OnlyOnRanToCompletion
;
322 const TaskContinuationOptions wrongCanceled
= TaskContinuationOptions
.NotOnCanceled
| TaskContinuationOptions
.OnlyOnCanceled
;
323 const TaskContinuationOptions wrongFaulted
= TaskContinuationOptions
.NotOnFaulted
| TaskContinuationOptions
.OnlyOnFaulted
;
325 if (((options
& wrongRan
) == wrongRan
) || ((options
& wrongCanceled
) == wrongCanceled
) || ((options
& wrongFaulted
) == wrongFaulted
))
326 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
328 // Already set the scheduler so that user can call Wait and that sort of stuff
329 continuation
.scheduler
= scheduler
;
330 continuation
.Status
= TaskStatus
.WaitingForActivation
;
332 ContinueWith (new TaskContinuation (continuation
, options
));
335 internal void ContinueWith (IContinuation continuation
)
338 continuation
.Execute ();
342 continuations
.Add (continuation
);
344 // Retry in case completion was achieved but event adding was too late
345 if (IsCompleted
&& continuations
.Remove (continuation
))
346 continuation
.Execute ();
349 internal void RemoveContinuation (IContinuation continuation
)
351 continuations
.Remove (continuation
);
354 static internal TaskCreationOptions
GetCreationOptions (TaskContinuationOptions kind
)
356 TaskCreationOptions options
= TaskCreationOptions
.None
;
357 if ((kind
& TaskContinuationOptions
.AttachedToParent
) > 0)
358 options
|= TaskCreationOptions
.AttachedToParent
;
359 if ((kind
& TaskContinuationOptions
.PreferFairness
) > 0)
360 options
|= TaskCreationOptions
.PreferFairness
;
361 if ((kind
& TaskContinuationOptions
.LongRunning
) > 0)
362 options
|= TaskCreationOptions
.LongRunning
;
368 #region Internal and protected thingies
369 internal void Schedule ()
371 Status
= TaskStatus
.WaitingToRun
;
372 scheduler
.QueueTask (this);
377 /* Allow scheduler to break fairness of deque ordering without
378 * breaking its semantic (the task can be executed twice but the
379 * second time it will return immediately
381 if (!executing
.TryRelaxedSet ())
384 // Disable CancellationToken direct cancellation
385 if (cancellationRegistration
!= null) {
386 cancellationRegistration
.Value
.Dispose ();
387 cancellationRegistration
= null;
390 // If Task are ran inline on the same thread we might trash these values
391 var saveCurrent
= current
;
392 var saveScheduler
= TaskScheduler
.Current
;
396 TaskScheduler
.Current
= HasFlag (creationOptions
, TaskCreationOptions
.HideScheduler
) ? TaskScheduler
.Default
: scheduler
;
398 TaskScheduler
.Current
= scheduler
;
401 if (!token
.IsCancellationRequested
) {
403 status
= TaskStatus
.Running
;
407 } catch (OperationCanceledException oce
) {
408 if (token
!= CancellationToken
.None
&& oce
.CancellationToken
== token
)
411 HandleGenericException (oce
);
412 } catch (Exception e
) {
413 HandleGenericException (e
);
419 if (saveCurrent
!= null)
420 current
= saveCurrent
;
421 if (saveScheduler
!= null)
422 TaskScheduler
.Current
= saveScheduler
;
426 internal bool TrySetCanceled ()
431 if (!executing
.TryRelaxedSet ()) {
432 var sw
= new SpinWait ();
443 internal bool TrySetException (AggregateException aggregate
)
448 if (!executing
.TryRelaxedSet ()) {
449 var sw
= new SpinWait ();
456 HandleGenericException (aggregate
);
460 internal bool TrySetExceptionObserved ()
462 if (exSlot
!= null) {
463 exSlot
.Observed
= true;
469 internal void Execute ()
474 internal void AddChild ()
476 if (childTasks
== null)
477 Interlocked
.CompareExchange (ref childTasks
, new CountdownEvent (1), null);
478 childTasks
.AddCount ();
481 internal void ChildCompleted (AggregateException childEx
)
483 if (childEx
!= null) {
484 if (ExceptionSlot
.ChildExceptions
== null)
485 Interlocked
.CompareExchange (ref ExceptionSlot
.ChildExceptions
, new ConcurrentQueue
<AggregateException
> (), null);
486 ExceptionSlot
.ChildExceptions
.Enqueue (childEx
);
489 if (childTasks
.Signal () && status
== TaskStatus
.WaitingForChildrenToComplete
) {
490 ProcessChildExceptions ();
491 Status
= exSlot
== null ? TaskStatus
.RanToCompletion
: TaskStatus
.Faulted
;
492 ProcessCompleteDelegates ();
493 if (parent
!= null &&
495 !HasFlag (parent
.CreationOptions
, TaskCreationOptions
.DenyChildAttach
) &&
497 HasFlag (creationOptions
, TaskCreationOptions
.AttachedToParent
))
498 parent
.ChildCompleted (this.Exception
);
504 if (IsContinuation
) {
505 invoker
.Invoke (contAncestor
, state
, this);
507 invoker
.Invoke (this, state
, this);
511 internal void Finish ()
513 // If there was children created and they all finished, we set the countdown
514 if (childTasks
!= null) {
515 if (childTasks
.Signal ())
516 ProcessChildExceptions (true);
519 // Don't override Canceled or Faulted
520 if (status
== TaskStatus
.Running
) {
521 if (childTasks
== null || childTasks
.IsSet
)
522 Status
= TaskStatus
.RanToCompletion
;
524 Status
= TaskStatus
.WaitingForChildrenToComplete
;
527 if (wait_handle
!= null)
530 // Tell parent that we are finished
531 if (parent
!= null && HasFlag (creationOptions
, TaskCreationOptions
.AttachedToParent
) &&
533 !HasFlag (parent
.CreationOptions
, TaskCreationOptions
.DenyChildAttach
) &&
535 status
!= TaskStatus
.WaitingForChildrenToComplete
) {
536 parent
.ChildCompleted (this.Exception
);
539 // Completions are already processed when task is canceled or faulted
540 if (status
== TaskStatus
.RanToCompletion
)
541 ProcessCompleteDelegates ();
543 // Reset the current thingies
546 if (TaskScheduler
.Current
== scheduler
)
547 TaskScheduler
.Current
= null;
549 if (cancellationRegistration
.HasValue
)
550 cancellationRegistration
.Value
.Dispose ();
553 void ProcessCompleteDelegates ()
555 if (continuations
.HasElements
) {
556 IContinuation continuation
;
557 while (continuations
.TryGetNextCompletion (out continuation
))
558 continuation
.Execute ();
562 void ProcessChildExceptions (bool isParent
= false)
564 if (exSlot
== null || exSlot
.ChildExceptions
== null)
567 if (ExceptionSlot
.Exception
== null)
568 exSlot
.Exception
= new AggregateException ();
570 AggregateException childEx
;
571 while (exSlot
.ChildExceptions
.TryDequeue (out childEx
))
572 exSlot
.Exception
.AddChildException (childEx
);
575 Status
= TaskStatus
.Faulted
;
576 ProcessCompleteDelegates ();
581 #region Cancel and Wait related method
583 internal void CancelReal ()
585 Status
= TaskStatus
.Canceled
;
587 if (wait_handle
!= null)
590 ProcessCompleteDelegates ();
593 void HandleGenericException (Exception e
)
595 HandleGenericException (new AggregateException (e
));
598 void HandleGenericException (AggregateException e
)
600 ExceptionSlot
.Exception
= e
;
601 Thread
.MemoryBarrier ();
602 Status
= TaskStatus
.Faulted
;
604 if (wait_handle
!= null)
607 ProcessCompleteDelegates ();
610 internal bool WaitOnChildren ()
612 if (Status
== TaskStatus
.WaitingForChildrenToComplete
&& childTasks
!= null) {
621 Wait (Timeout
.Infinite
, CancellationToken
.None
);
624 public void Wait (CancellationToken cancellationToken
)
626 Wait (Timeout
.Infinite
, cancellationToken
);
629 public bool Wait (TimeSpan timeout
)
631 return Wait (CheckTimeout (timeout
), CancellationToken
.None
);
634 public bool Wait (int millisecondsTimeout
)
636 return Wait (millisecondsTimeout
, CancellationToken
.None
);
639 public bool Wait (int millisecondsTimeout
, CancellationToken cancellationToken
)
641 if (millisecondsTimeout
< -1)
642 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
647 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
648 if (Status
== TaskStatus
.WaitingToRun
&& millisecondsTimeout
== Timeout
.Infinite
&& scheduler
!= null && !cancellationToken
.CanBeCanceled
)
649 scheduler
.RunInline (this, true);
652 var continuation
= new ManualResetContinuation ();
654 ContinueWith (continuation
);
655 result
= continuation
.Event
.Wait (millisecondsTimeout
, cancellationToken
);
658 RemoveContinuation (continuation
);
659 continuation
.Dispose ();
665 throw new AggregateException (new TaskCanceledException (this));
667 var exception
= Exception
;
668 if (exception
!= null)
674 public static void WaitAll (params Task
[] tasks
)
676 WaitAll (tasks
, Timeout
.Infinite
, CancellationToken
.None
);
679 public static void WaitAll (Task
[] tasks
, CancellationToken cancellationToken
)
681 WaitAll (tasks
, Timeout
.Infinite
, cancellationToken
);
684 public static bool WaitAll (Task
[] tasks
, TimeSpan timeout
)
686 return WaitAll (tasks
, CheckTimeout (timeout
), CancellationToken
.None
);
689 public static bool WaitAll (Task
[] tasks
, int millisecondsTimeout
)
691 return WaitAll (tasks
, millisecondsTimeout
, CancellationToken
.None
);
694 public static bool WaitAll (Task
[] tasks
, int millisecondsTimeout
, CancellationToken cancellationToken
)
697 throw new ArgumentNullException ("tasks");
700 foreach (var t
in tasks
) {
702 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
704 result
&= t
.Status
== TaskStatus
.RanToCompletion
;
708 var continuation
= new CountdownContinuation (tasks
.Length
);
710 foreach (var t
in tasks
)
711 t
.ContinueWith (continuation
);
713 result
= continuation
.Event
.Wait (millisecondsTimeout
, cancellationToken
);
715 List
<Exception
> exceptions
= null;
717 foreach (var t
in tasks
) {
719 if (t
.Status
== TaskStatus
.RanToCompletion
)
721 if (exceptions
== null)
722 exceptions
= new List
<Exception
> ();
723 if (t
.Exception
!= null)
724 exceptions
.AddRange (t
.Exception
.InnerExceptions
);
726 exceptions
.Add (new TaskCanceledException (t
));
728 t
.RemoveContinuation (continuation
);
732 continuation
.Dispose ();
734 if (exceptions
!= null)
735 throw new AggregateException (exceptions
);
742 public static int WaitAny (params Task
[] tasks
)
744 return WaitAny (tasks
, Timeout
.Infinite
, CancellationToken
.None
);
747 public static int WaitAny (Task
[] tasks
, TimeSpan timeout
)
749 return WaitAny (tasks
, CheckTimeout (timeout
));
752 public static int WaitAny (Task
[] tasks
, int millisecondsTimeout
)
754 return WaitAny (tasks
, millisecondsTimeout
, CancellationToken
.None
);
757 public static int WaitAny (Task
[] tasks
, CancellationToken cancellationToken
)
759 return WaitAny (tasks
, Timeout
.Infinite
, cancellationToken
);
762 public static int WaitAny (Task
[] tasks
, int millisecondsTimeout
, CancellationToken cancellationToken
)
765 throw new ArgumentNullException ("tasks");
766 if (millisecondsTimeout
< -1)
767 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
768 CheckForNullTasks (tasks
);
770 if (tasks
.Length
> 0) {
771 var continuation
= new ManualResetContinuation ();
774 for (int i
= 0; i
< tasks
.Length
; i
++) {
778 t
.ContinueWith (continuation
);
781 if (!(result
= continuation
.Event
.Wait (millisecondsTimeout
, cancellationToken
)))
785 foreach (var t
in tasks
)
786 t
.RemoveContinuation (continuation
);
787 continuation
.Dispose ();
791 int firstFinished
= -1;
792 for (int i
= 0; i
< tasks
.Length
; i
++) {
800 return firstFinished
;
803 static int CheckTimeout (TimeSpan timeout
)
806 return checked ((int)timeout
.TotalMilliseconds
);
807 } catch (System
.OverflowException
) {
808 throw new ArgumentOutOfRangeException ("timeout");
812 static void CheckForNullTasks (Task
[] tasks
)
814 foreach (var t
in tasks
)
816 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
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
836 if (cancellationRegistration
!= null)
837 cancellationRegistration
.Value
.Dispose ();
838 if (wait_handle
!= null)
839 wait_handle
.Dispose ();
849 Task
ContinueWith (Action
<Task
, object> continuationAction
, object state
, CancellationToken cancellationToken
,
850 TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
852 if (continuationAction
== null)
853 throw new ArgumentNullException ("continuationAction");
854 if (scheduler
== null)
855 throw new ArgumentNullException ("scheduler");
857 Task continuation
= new Task (TaskActionInvoker
.Create (continuationAction
),
858 state
, cancellationToken
,
859 GetCreationOptions (continuationOptions
),
862 ContinueWithCore (continuation
, continuationOptions
, scheduler
);
869 public ConfiguredTaskAwaitable
ConfigureAwait (bool continueOnCapturedContext
)
871 return new ConfiguredTaskAwaitable (this, continueOnCapturedContext
);
874 public Task
ContinueWith (Action
<Task
, object> continuationAction
, object state
)
876 return ContinueWith (continuationAction
, state
, CancellationToken
.None
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
879 public Task
ContinueWith (Action
<Task
, object> continuationAction
, object state
, CancellationToken cancellationToken
)
881 return ContinueWith (continuationAction
, state
, cancellationToken
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
884 public Task
ContinueWith (Action
<Task
, object> continuationAction
, object state
, TaskContinuationOptions continuationOptions
)
886 return ContinueWith (continuationAction
, state
, CancellationToken
.None
, continuationOptions
, TaskScheduler
.Current
);
889 public Task
ContinueWith (Action
<Task
, object> continuationAction
, object state
, TaskScheduler scheduler
)
891 return ContinueWith (continuationAction
, state
, CancellationToken
.None
, TaskContinuationOptions
.None
, scheduler
);
894 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, object, TResult
> continuationFunction
, object state
)
896 return ContinueWith
<TResult
> (continuationFunction
, state
, CancellationToken
.None
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
899 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, object, TResult
> continuationFunction
, object state
, TaskContinuationOptions continuationOptions
)
901 return ContinueWith
<TResult
> (continuationFunction
, state
, CancellationToken
.None
, continuationOptions
, TaskScheduler
.Current
);
904 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, object, TResult
> continuationFunction
, object state
, CancellationToken cancellationToken
)
906 return ContinueWith
<TResult
> (continuationFunction
, state
, cancellationToken
, TaskContinuationOptions
.None
, TaskScheduler
.Current
);
909 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, object, TResult
> continuationFunction
, object state
, TaskScheduler scheduler
)
911 return ContinueWith
<TResult
> (continuationFunction
, state
, CancellationToken
.None
, TaskContinuationOptions
.None
, scheduler
);
914 public Task
<TResult
> ContinueWith
<TResult
> (Func
<Task
, object, TResult
> continuationFunction
, object state
, CancellationToken cancellationToken
,
915 TaskContinuationOptions continuationOptions
, TaskScheduler scheduler
)
917 if (continuationFunction
== null)
918 throw new ArgumentNullException ("continuationFunction");
919 if (scheduler
== null)
920 throw new ArgumentNullException ("scheduler");
922 var t
= new Task
<TResult
> (TaskActionInvoker
.Create (continuationFunction
),
925 GetCreationOptions (continuationOptions
),
929 ContinueWithCore (t
, continuationOptions
, scheduler
);
934 public static Task
Delay (int millisecondsDelay
)
936 return Delay (millisecondsDelay
, CancellationToken
.None
);
939 public static Task
Delay (TimeSpan delay
)
941 return Delay (CheckTimeout (delay
), CancellationToken
.None
);
944 public static Task
Delay (TimeSpan delay
, CancellationToken cancellationToken
)
946 return Delay (CheckTimeout (delay
), cancellationToken
);
949 public static Task
Delay (int millisecondsDelay
, CancellationToken cancellationToken
)
951 if (millisecondsDelay
< -1)
952 throw new ArgumentOutOfRangeException ("millisecondsDelay");
954 var task
= new Task (TaskActionInvoker
.Delay
, millisecondsDelay
, cancellationToken
, TaskCreationOptions
.None
, null, TaskConstants
.Finished
);
955 task
.SetupScheduler (TaskScheduler
.Current
);
957 if (millisecondsDelay
!= Timeout
.Infinite
)
958 task
.scheduler
.QueueTask (task
);
963 public static Task
<TResult
> FromResult
<TResult
> (TResult result
)
965 var tcs
= new TaskCompletionSource
<TResult
> ();
966 tcs
.SetResult (result
);
970 public TaskAwaiter
GetAwaiter ()
972 return new TaskAwaiter (this);
975 public static Task
Run (Action action
)
977 return Run (action
, CancellationToken
.None
);
980 public static Task
Run (Action action
, CancellationToken cancellationToken
)
982 if (cancellationToken
.IsCancellationRequested
)
983 return TaskConstants
.Canceled
;
985 return Task
.Factory
.StartNew (action
, cancellationToken
, TaskCreationOptions
.DenyChildAttach
, TaskScheduler
.Default
);
988 public static Task
Run (Func
<Task
> function
)
990 return Run (function
, CancellationToken
.None
);
993 public static Task
Run (Func
<Task
> function
, CancellationToken cancellationToken
)
995 if (cancellationToken
.IsCancellationRequested
)
996 return TaskConstants
.Canceled
;
998 return TaskExtensionsImpl
.Unwrap (Task
.Factory
.StartNew (function
, cancellationToken
, TaskCreationOptions
.DenyChildAttach
, TaskScheduler
.Default
));
1001 public static Task
<TResult
> Run
<TResult
> (Func
<TResult
> function
)
1003 return Run (function
, CancellationToken
.None
);
1006 public static Task
<TResult
> Run
<TResult
> (Func
<TResult
> function
, CancellationToken cancellationToken
)
1008 if (cancellationToken
.IsCancellationRequested
)
1009 return TaskConstants
<TResult
>.Canceled
;
1011 return Task
.Factory
.StartNew (function
, cancellationToken
, TaskCreationOptions
.DenyChildAttach
, TaskScheduler
.Default
);
1014 public static Task
<TResult
> Run
<TResult
> (Func
<Task
<TResult
>> function
)
1016 return Run (function
, CancellationToken
.None
);
1019 public static Task
<TResult
> Run
<TResult
> (Func
<Task
<TResult
>> function
, CancellationToken cancellationToken
)
1021 if (cancellationToken
.IsCancellationRequested
)
1022 return TaskConstants
<TResult
>.Canceled
;
1024 return TaskExtensionsImpl
.Unwrap (Task
.Factory
.StartNew (function
, cancellationToken
, TaskCreationOptions
.DenyChildAttach
, TaskScheduler
.Default
));
1027 public static Task
WhenAll (params Task
[] tasks
)
1030 throw new ArgumentNullException ("tasks");
1032 return WhenAllCore (tasks
);
1035 public static Task
WhenAll (IEnumerable
<Task
> tasks
)
1038 throw new ArgumentNullException ("tasks");
1040 // Call ToList on input enumeration or we end up
1041 // enumerating it more than once
1042 return WhenAllCore (new List
<Task
> (tasks
));
1045 public static Task
<TResult
[]> WhenAll
<TResult
> (params Task
<TResult
>[] tasks
)
1048 throw new ArgumentNullException ("tasks");
1050 return WhenAllCore
<TResult
> (tasks
);
1053 public static Task
<TResult
[]> WhenAll
<TResult
> (IEnumerable
<Task
<TResult
>> tasks
)
1056 throw new ArgumentNullException ("tasks");
1058 // Call ToList on input enumeration or we end up
1059 // enumerating it more than once
1060 return WhenAllCore
<TResult
> (new List
<Task
<TResult
>> (tasks
));
1063 internal static Task
<TResult
[]> WhenAllCore
<TResult
> (IList
<Task
<TResult
>> tasks
)
1065 foreach (var t
in tasks
) {
1067 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1070 var task
= new Task
<TResult
[]> (TaskActionInvoker
.Empty
, null, CancellationToken
.None
, TaskCreationOptions
.None
, null, TaskConstants
.Finished
);
1071 task
.SetupScheduler (TaskScheduler
.Current
);
1073 var continuation
= new WhenAllContinuation
<TResult
> (task
, tasks
);
1074 foreach (var t
in tasks
)
1075 t
.ContinueWith (continuation
);
1080 public static Task
<Task
> WhenAny (params Task
[] tasks
)
1083 throw new ArgumentNullException ("tasks");
1085 return WhenAnyCore (tasks
);
1088 public static Task
<Task
> WhenAny (IEnumerable
<Task
> tasks
)
1091 throw new ArgumentNullException ("tasks");
1093 return WhenAnyCore (new List
<Task
> (tasks
));
1096 public static Task
<Task
<TResult
>> WhenAny
<TResult
> (params Task
<TResult
>[] tasks
)
1099 throw new ArgumentNullException ("tasks");
1101 return WhenAnyCore
<TResult
> (tasks
);
1104 public static Task
<Task
<TResult
>> WhenAny
<TResult
> (IEnumerable
<Task
<TResult
>> tasks
)
1107 throw new ArgumentNullException ("tasks");
1109 return WhenAnyCore
<TResult
> (new List
<Task
<TResult
>> (tasks
));
1112 static Task
<Task
<TResult
>> WhenAnyCore
<TResult
> (IList
<Task
<TResult
>> tasks
)
1114 if (tasks
.Count
== 0)
1115 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1117 int completed_index
= -1;
1118 for (int i
= 0; i
< tasks
.Count
; ++i
) {
1121 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1123 if (t
.IsCompleted
&& completed_index
< 0)
1124 completed_index
= i
;
1127 var task
= new Task
<Task
<TResult
>> (TaskActionInvoker
.Empty
, null, CancellationToken
.None
, TaskCreationOptions
.None
, null, TaskConstants
.Finished
);
1129 if (completed_index
> 0) {
1130 task
.TrySetResult (tasks
[completed_index
]);
1134 task
.SetupScheduler (TaskScheduler
.Current
);
1136 var continuation
= new WhenAnyContinuation
<Task
<TResult
>> (task
, tasks
);
1137 foreach (var t
in tasks
)
1138 t
.ContinueWith (continuation
);
1143 public static YieldAwaitable
Yield ()
1145 return new YieldAwaitable ();
1149 internal static Task
WhenAllCore (IList
<Task
> tasks
)
1151 bool all_completed
= true;
1152 foreach (var t
in tasks
) {
1154 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1156 all_completed
&= t
.Status
== TaskStatus
.RanToCompletion
;
1160 return TaskConstants
.Finished
;
1162 var task
= new Task (TaskActionInvoker
.Empty
, null, CancellationToken
.None
, TaskCreationOptions
.None
, null, TaskConstants
.Finished
);
1163 task
.SetupScheduler (TaskScheduler
.Current
);
1165 var continuation
= new WhenAllContinuation (task
, tasks
);
1166 foreach (var t
in tasks
)
1167 t
.ContinueWith (continuation
);
1172 internal static Task
<Task
> WhenAnyCore (IList
<Task
> tasks
)
1174 if (tasks
.Count
== 0)
1175 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1177 int completed_index
= -1;
1178 for (int i
= 0; i
< tasks
.Count
; ++i
) {
1181 throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1183 if (t
.IsCompleted
&& completed_index
< 0)
1184 completed_index
= i
;
1187 var task
= new Task
<Task
> (TaskActionInvoker
.Empty
, null, CancellationToken
.None
, TaskCreationOptions
.None
, null, TaskConstants
.Finished
);
1189 if (completed_index
> 0) {
1190 task
.TrySetResult (tasks
[completed_index
]);
1194 task
.SetupScheduler (TaskScheduler
.Current
);
1196 var continuation
= new WhenAnyContinuation
<Task
> (task
, tasks
);
1197 foreach (var t
in tasks
)
1198 t
.ContinueWith (continuation
);
1204 internal CancellationToken CancellationToken
{
1210 public static TaskFactory Factory
{
1212 return defaultFactory
;
1216 public static int? CurrentId
{
1219 return t
== null ? (int?)null : t
.Id
;
1223 public AggregateException Exception
{
1227 exSlot
.Observed
= true;
1228 return exSlot
.Exception
;
1232 public bool IsCanceled
{
1234 return status
== TaskStatus
.Canceled
;
1238 public bool IsCompleted
{
1240 return status
>= TaskStatus
.RanToCompletion
;
1244 public bool IsFaulted
{
1246 return status
== TaskStatus
.Faulted
;
1250 public TaskCreationOptions CreationOptions
{
1252 return creationOptions
& MaxTaskCreationOptions
;
1256 public TaskStatus Status
{
1262 Thread
.MemoryBarrier ();
1266 TaskExceptionSlot ExceptionSlot
{
1270 Interlocked
.CompareExchange (ref exSlot
, new TaskExceptionSlot (this), null);
1275 public object AsyncState
{
1281 bool IAsyncResult
.CompletedSynchronously
{
1287 WaitHandle IAsyncResult
.AsyncWaitHandle
{
1289 if (invoker
== null)
1290 throw new ObjectDisposedException (GetType ().ToString ());
1292 if (wait_handle
== null)
1293 Interlocked
.CompareExchange (ref wait_handle
, new ManualResetEvent (IsCompleted
), null);
1305 bool IsContinuation
{
1307 return contAncestor
!= null;
1311 internal Task ContinuationAncestor
{
1313 return contAncestor
;
1317 internal string DisplayActionMethod
{
1319 Delegate d
= invoker
.Action
;
1320 return d
== null ? "<none>" : d
.Method
.ToString ();