Task.cs
Go to the documentation of this file.
1 //
2 // Task.cs
3 //
4 // Authors:
5 // Marek Safar <marek.safar@gmail.com>
6 // Jérémie Laval <jeremie dot laval at xamarin dot com>
7 //
8 // Copyright (c) 2008 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
10 //
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:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
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
27 // THE SOFTWARE.
28 //
29 //
30 
31 #if NET_4_0
32 
33 using System;
34 using System.Threading;
38 
39 namespace System.Threading.Tasks
40 {
41  [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
42  [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
43  public class Task : IDisposable, IAsyncResult
44  {
45  // With this attribute each thread has its own value so that it's correct for our Schedule code
46  // and for Parent property.
47  [System.ThreadStatic]
48  static Task current;
49  [System.ThreadStatic]
50  static Action<Task> childWorkAdder;
51 
52  // parent is the outer task in which this task is created
53  readonly Task parent;
54  // contAncestor is the Task on which this continuation was setup
55  readonly Task contAncestor;
56 
57  static int id = -1;
58  static readonly TaskFactory defaultFactory = new TaskFactory ();
59 
60  CountdownEvent childTasks;
61 
62  int taskId;
63  TaskCreationOptions creationOptions;
64 
65  internal TaskScheduler scheduler;
66 
67  TaskExceptionSlot exSlot;
68 
69  TaskStatus status;
70 
71  TaskActionInvoker invoker;
72  object state;
73  internal AtomicBooleanValue executing;
74 
75  TaskCompletionQueue<IContinuation> continuations;
76 
77  CancellationToken token;
78  CancellationTokenRegistration? cancellationRegistration;
79 
80  internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
81 
82  const TaskCreationOptions MaxTaskCreationOptions =
83 #if NET_4_5
84  TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
85 #endif
86  TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
87 
88  public Task (Action action)
89  : this (action, TaskCreationOptions.None)
90  {
91 
92  }
93 
94  public Task (Action action, TaskCreationOptions creationOptions)
95  : this (action, CancellationToken.None, creationOptions)
96  {
97 
98  }
99 
100  public Task (Action action, CancellationToken cancellationToken)
101  : this (action, cancellationToken, TaskCreationOptions.None)
102  {
103 
104  }
105 
106  public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
107  : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
108  {
109  if (action == null)
110  throw new ArgumentNullException ("action");
111  if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
112  throw new ArgumentOutOfRangeException ("creationOptions");
113  }
114 
115  public Task (Action<object> action, object state)
116  : this (action, state, TaskCreationOptions.None)
117  {
118  }
119 
120  public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
121  : this (action, state, CancellationToken.None, creationOptions)
122  {
123  }
124 
125  public Task (Action<object> action, object state, CancellationToken cancellationToken)
126  : this (action, state, cancellationToken, TaskCreationOptions.None)
127  {
128  }
129 
130  public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
131  : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
132  {
133  if (action == null)
134  throw new ArgumentNullException ("action");
135  if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
136  throw new ArgumentOutOfRangeException ("creationOptions");
137  }
138 
139  // Spicy Pixel: Recent compiler changes do not allow delegates passed to base() to access 'this'.
140  // So we add protected members to update the task action later.
141  protected void SetAction (Action action)
142  {
143  this.invoker = TaskActionInvoker.Create(action);
144  }
145 
146  protected void SetAction (Action<object> action)
147  {
148  this.invoker = TaskActionInvoker.Create(action);
149  }
150 
151  internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
152  TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
153  {
154  this.invoker = invoker;
155  this.creationOptions = creationOptions;
156  this.state = state;
157  this.taskId = Interlocked.Increment (ref id);
158  this.token = cancellationToken;
159  this.parent = parent = parent == null ? current : parent;
160  this.contAncestor = contAncestor;
161  this.status = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
162 
163  // Process creationOptions
164 #if NET_4_5
165  if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
166  && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
167 #else
168  if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
169 #endif
170  parent.AddChild ();
171 
172  if (token.CanBeCanceled && !ignoreCancellation)
173  cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
174  }
175 
176  static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
177  {
178  return (opt & member) == member;
179  }
180 
181  #region Start
182  public void Start ()
183  {
184  Start (TaskScheduler.Current);
185  }
186 
187  public void Start (TaskScheduler scheduler)
188  {
189  if (scheduler == null)
190  throw new ArgumentNullException ("scheduler");
191 
192  if (status >= TaskStatus.WaitingToRun)
193  throw new InvalidOperationException ("The Task is not in a valid state to be started.");
194 
195  if (IsContinuation)
196  throw new InvalidOperationException ("Start may not be called on a continuation task");
197 
198  SetupScheduler (scheduler);
199  Schedule ();
200  }
201 
202  internal void SetupScheduler (TaskScheduler scheduler)
203  {
204  this.scheduler = scheduler;
205  Status = TaskStatus.WaitingForActivation;
206  }
207 
208  public void RunSynchronously ()
209  {
210  RunSynchronously (TaskScheduler.Current);
211  }
212 
213  public void RunSynchronously (TaskScheduler scheduler)
214  {
215  if (scheduler == null)
216  throw new ArgumentNullException ("scheduler");
217 
218  if (Status > TaskStatus.WaitingForActivation)
219  throw new InvalidOperationException ("The task is not in a valid state to be started");
220 
221  if (IsContinuation)
222  throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
223 
224  RunSynchronouslyCore (scheduler);
225  }
226 
227  internal void RunSynchronouslyCore (TaskScheduler scheduler)
228  {
229  SetupScheduler (scheduler);
230  var saveStatus = status;
231  Status = TaskStatus.WaitingToRun;
232 
233  try {
234  if (scheduler.RunInline (this, false))
235  return;
236  } catch (Exception inner) {
237  throw new TaskSchedulerException (inner);
238  }
239 
240  Status = saveStatus;
241  Start (scheduler);
242  Wait ();
243  }
244  #endregion
245 
246  #region ContinueWith
247  public Task ContinueWith (Action<Task> continuationAction)
248  {
249  return ContinueWith (continuationAction, TaskContinuationOptions.None);
250  }
251 
252  public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
253  {
254  return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
255  }
256 
257  public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
258  {
259  return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
260  }
261 
262  public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
263  {
264  return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
265  }
266 
267  public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
268  {
269  if (continuationAction == null)
270  throw new ArgumentNullException ("continuationAction");
271  if (scheduler == null)
272  throw new ArgumentNullException ("scheduler");
273 
274  return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
275  }
276 
277  internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
278  {
279  var lazyCancellation = false;
280 #if NET_4_5
281  lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
282 #endif
283  var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
284  ContinueWithCore (continuation, continuationOptions, scheduler);
285 
286  return continuation;
287  }
288 
289  public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
290  {
291  return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
292  }
293 
294  public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
295  {
296  return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
297  }
298 
299  public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
300  {
301  return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
302  }
303 
304  public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
305  {
306  return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
307  }
308 
309  public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
310  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
311  {
312  if (continuationFunction == null)
313  throw new ArgumentNullException ("continuationFunction");
314  if (scheduler == null)
315  throw new ArgumentNullException ("scheduler");
316 
317  return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
318  }
319 
320  internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
321  {
322  var lazyCancellation = false;
323 #if NET_4_5
324  lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
325 #endif
326  var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
327  ContinueWithCore (continuation, continuationOptions, scheduler);
328 
329  return continuation;
330  }
331 
332  internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
333  {
334  const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
335  const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
336  const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
337 
338  if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
339  throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
340 
341  // Already set the scheduler so that user can call Wait and that sort of stuff
342  continuation.scheduler = scheduler;
343  continuation.Status = TaskStatus.WaitingForActivation;
344 
345  ContinueWith (new TaskContinuation (continuation, options));
346  }
347 
348  internal void ContinueWith (IContinuation continuation)
349  {
350  if (IsCompleted) {
351  continuation.Execute ();
352  return;
353  }
354 
355  continuations.Add (continuation);
356 
357  // Retry in case completion was achieved but event adding was too late
358  if (IsCompleted && continuations.Remove (continuation))
359  continuation.Execute ();
360  }
361 
362  internal void RemoveContinuation (IContinuation continuation)
363  {
364  continuations.Remove (continuation);
365  }
366 
367  static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
368  {
370  if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
371  options |= TaskCreationOptions.AttachedToParent;
372  if ((kind & TaskContinuationOptions.PreferFairness) > 0)
373  options |= TaskCreationOptions.PreferFairness;
374  if ((kind & TaskContinuationOptions.LongRunning) > 0)
375  options |= TaskCreationOptions.LongRunning;
376 
377  return options;
378  }
379  #endregion
380 
381  #region Internal and protected thingies
382  internal void Schedule ()
383  {
384  Status = TaskStatus.WaitingToRun;
385 
386  // If worker is null it means it is a local one, revert to the old behavior
387  // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
388  if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
389  scheduler.QueueTask (this);
390  } else {
391  /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom
392  * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
393  * the correct Thread during the creation
394  */
395  childWorkAdder (this);
396  }
397  }
398 
399  void ThreadStart ()
400  {
401  /* Allow scheduler to break fairness of deque ordering without
402  * breaking its semantic (the task can be executed twice but the
403  * second time it will return immediately
404  */
405  if (!executing.TryRelaxedSet ())
406  return;
407 
408  // Disable CancellationToken direct cancellation
409  if (cancellationRegistration != null) {
410  cancellationRegistration.Value.Dispose ();
411  cancellationRegistration = null;
412  }
413 
414  // If Task are ran inline on the same thread we might trash these values
415  var saveCurrent = current;
416  var saveScheduler = TaskScheduler.Current;
417 
418  current = this;
419 #if NET_4_5
420  TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
421 #else
422  TaskScheduler.Current = scheduler;
423 #endif
424 
425  if (!token.IsCancellationRequested) {
426 
427  status = TaskStatus.Running;
428 
429  try {
430  InnerInvoke ();
431  } catch (Threading.OperationCanceledException oce) {
432  if (token != CancellationToken.None && oce.CancellationToken == token)
433  CancelReal ();
434  else
435  HandleGenericException (oce);
436  } catch (Exception e) {
437  HandleGenericException (e);
438  }
439  } else {
440  CancelReal ();
441  }
442 
443  if (saveCurrent != null)
444  current = saveCurrent;
445  if (saveScheduler != null)
446  TaskScheduler.Current = saveScheduler;
447  Finish ();
448  }
449 
450  internal bool TrySetCanceled ()
451  {
452  if (IsCompleted)
453  return false;
454 
455  if (!executing.TryRelaxedSet ()) {
456  var sw = new SpinWait ();
457  while (!IsCompleted)
458  sw.SpinOnce ();
459 
460  return false;
461  }
462 
463  CancelReal ();
464  return true;
465  }
466 
467  internal bool TrySetException (AggregateException aggregate)
468  {
469  if (IsCompleted)
470  return false;
471 
472  if (!executing.TryRelaxedSet ()) {
473  var sw = new SpinWait ();
474  while (!IsCompleted)
475  sw.SpinOnce ();
476 
477  return false;
478  }
479 
480  HandleGenericException (aggregate);
481  return true;
482  }
483 
484  internal bool TrySetExceptionObserved ()
485  {
486  if (exSlot != null) {
487  exSlot.Observed = true;
488  return true;
489  }
490  return false;
491  }
492 
493  internal void Execute ()
494  {
495  ThreadStart ();
496  }
497 
498  internal void AddChild ()
499  {
500  if (childTasks == null)
501  AotInterlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
502  childTasks.AddCount ();
503  }
504 
505  internal void ChildCompleted (AggregateException childEx)
506  {
507  if (childEx != null) {
508  if (ExceptionSlot.ChildExceptions == null)
509  AotInterlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
510  ExceptionSlot.ChildExceptions.Enqueue (childEx);
511  }
512 
513  if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
514  ProcessChildExceptions ();
515  Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
516  ProcessCompleteDelegates ();
517  if (parent != null &&
518 #if NET_4_5
519  !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
520 #endif
521  HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
522  parent.ChildCompleted (this.Exception);
523  }
524  }
525 
526  void InnerInvoke ()
527  {
528  if (IsContinuation) {
529  invoker.Invoke (contAncestor, state, this);
530  } else {
531  invoker.Invoke (this, state, this);
532  }
533  }
534 
535  internal void Finish ()
536  {
537  // If there was children created and they all finished, we set the countdown
538  if (childTasks != null) {
539  if (childTasks.Signal ())
540  ProcessChildExceptions (true);
541  }
542 
543  // Don't override Canceled or Faulted
544  if (status == TaskStatus.Running) {
545  if (childTasks == null || childTasks.IsSet)
546  Status = TaskStatus.RanToCompletion;
547  else
548  Status = TaskStatus.WaitingForChildrenToComplete;
549  }
550 
551  // Tell parent that we are finished
552  if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
553 #if NET_4_5
554  !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
555 #endif
556  status != TaskStatus.WaitingForChildrenToComplete) {
557  parent.ChildCompleted (this.Exception);
558  }
559 
560  // Completions are already processed when task is canceled or faulted
561  if (status == TaskStatus.RanToCompletion)
562  ProcessCompleteDelegates ();
563 
564  // Reset the current thingies
565  if (current == this)
566  current = null;
567  if (TaskScheduler.Current == scheduler)
568  TaskScheduler.Current = null;
569 
570  if (cancellationRegistration.HasValue)
571  cancellationRegistration.Value.Dispose ();
572  }
573 
574  void ProcessCompleteDelegates ()
575  {
576  if (continuations.HasElements) {
577  IContinuation continuation;
578  while (continuations.TryGetNextCompletion (out continuation))
579  continuation.Execute ();
580  }
581  }
582 
583  void ProcessChildExceptions (bool isParent = false)
584  {
585  if (exSlot == null || exSlot.ChildExceptions == null)
586  return;
587 
588  if (ExceptionSlot.Exception == null)
589  exSlot.Exception = new AggregateException ();
590 
591  AggregateException childEx;
592  while (exSlot.ChildExceptions.TryDequeue (out childEx))
593  exSlot.Exception.AddChildException (childEx);
594 
595  if (isParent) {
596  Status = TaskStatus.Faulted;
597  ProcessCompleteDelegates ();
598  }
599  }
600  #endregion
601 
602  #region Cancel and Wait related method
603 
604  internal void CancelReal ()
605  {
606  Status = TaskStatus.Canceled;
607  ProcessCompleteDelegates ();
608  }
609 
610  void HandleGenericException (Exception e)
611  {
612  HandleGenericException (new AggregateException (e));
613  }
614 
615  void HandleGenericException (AggregateException e)
616  {
617  ExceptionSlot.Exception = e;
618  Thread.MemoryBarrier ();
619  Status = TaskStatus.Faulted;
620  ProcessCompleteDelegates ();
621  }
622 
623  internal bool WaitOnChildren ()
624  {
625  if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
626  childTasks.Wait ();
627  return true;
628  }
629  return false;
630  }
631 
632  public void Wait ()
633  {
634  Wait (Timeout.Infinite, CancellationToken.None);
635  }
636 
637  public void Wait (CancellationToken cancellationToken)
638  {
639  Wait (Timeout.Infinite, cancellationToken);
640  }
641 
642  public bool Wait (TimeSpan timeout)
643  {
644  return Wait (CheckTimeout (timeout), CancellationToken.None);
645  }
646 
647  public bool Wait (int millisecondsTimeout)
648  {
649  return Wait (millisecondsTimeout, CancellationToken.None);
650  }
651 
652  public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
653  {
654  if (millisecondsTimeout < -1)
655  throw new ArgumentOutOfRangeException ("millisecondsTimeout");
656 
657  bool result = true;
658 
659  if (!IsCompleted) {
660  // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
661  if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
662  scheduler.RunInline (this, true);
663 
664  if (!IsCompleted) {
665  var continuation = new ManualResetContinuation ();
666  try {
667  ContinueWith (continuation);
668  result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
669  } finally {
670  if (!result)
671  RemoveContinuation (continuation);
672  continuation.Dispose ();
673  }
674  }
675  }
676 
677  if (IsCanceled)
678  throw new AggregateException (new TaskCanceledException (this));
679 
680  var exception = Exception;
681  if (exception != null)
682  throw exception;
683 
684  return result;
685  }
686 
687  public static void WaitAll (params Task[] tasks)
688  {
689  WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
690  }
691 
692  public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
693  {
694  WaitAll (tasks, Timeout.Infinite, cancellationToken);
695  }
696 
697  public static bool WaitAll (Task[] tasks, TimeSpan timeout)
698  {
699  return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
700  }
701 
702  public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
703  {
704  return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
705  }
706 
707  public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
708  {
709  if (tasks == null)
710  throw new ArgumentNullException ("tasks");
711 
712  bool result = true;
713  foreach (var t in tasks) {
714  if (t == null)
715  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
716 
717  result &= t.Status == TaskStatus.RanToCompletion;
718  }
719 
720  if (!result) {
721  var continuation = new CountdownContinuation (tasks.Length);
722  try {
723  foreach (var t in tasks)
724  t.ContinueWith (continuation);
725 
726  result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
727  } finally {
728  List<Exception> exceptions = null;
729 
730  foreach (var t in tasks) {
731  if (result) {
732  if (t.Status == TaskStatus.RanToCompletion)
733  continue;
734  if (exceptions == null)
735  exceptions = new List<Exception> ();
736  if (t.Exception != null)
737  exceptions.AddRange (t.Exception.InnerExceptions);
738  else
739  exceptions.Add (new TaskCanceledException (t));
740  } else {
741  t.RemoveContinuation (continuation);
742  }
743  }
744 
745  continuation.Dispose ();
746 
747  if (exceptions != null)
748  throw new AggregateException (exceptions);
749  }
750  }
751 
752  return result;
753  }
754 
755  public static int WaitAny (params Task[] tasks)
756  {
757  return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
758  }
759 
760  public static int WaitAny (Task[] tasks, TimeSpan timeout)
761  {
762  return WaitAny (tasks, CheckTimeout (timeout));
763  }
764 
765  public static int WaitAny (Task[] tasks, int millisecondsTimeout)
766  {
767  return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
768  }
769 
770  public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
771  {
772  return WaitAny (tasks, Timeout.Infinite, cancellationToken);
773  }
774 
775  public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
776  {
777  if (tasks == null)
778  throw new ArgumentNullException ("tasks");
779  if (millisecondsTimeout < -1)
780  throw new ArgumentOutOfRangeException ("millisecondsTimeout");
781  CheckForNullTasks (tasks);
782 
783  if (tasks.Length > 0) {
784  var continuation = new ManualResetContinuation ();
785  bool result = false;
786  try {
787  for (int i = 0; i < tasks.Length; i++) {
788  var t = tasks[i];
789  if (t.IsCompleted)
790  return i;
791  t.ContinueWith (continuation);
792  }
793 
794  if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
795  return -1;
796  } finally {
797  if (!result)
798  foreach (var t in tasks)
799  t.RemoveContinuation (continuation);
800  continuation.Dispose ();
801  }
802  }
803 
804  int firstFinished = -1;
805  for (int i = 0; i < tasks.Length; i++) {
806  var t = tasks[i];
807  if (t.IsCompleted) {
808  firstFinished = i;
809  break;
810  }
811  }
812 
813  return firstFinished;
814  }
815 
816  static int CheckTimeout (TimeSpan timeout)
817  {
818  try {
819  return checked ((int)timeout.TotalMilliseconds);
820  } catch (System.OverflowException) {
821  throw new ArgumentOutOfRangeException ("timeout");
822  }
823  }
824 
825  static void CheckForNullTasks (Task[] tasks)
826  {
827  foreach (var t in tasks)
828  if (t == null)
829  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
830  }
831  #endregion
832 
833  #region Dispose
834  public void Dispose ()
835  {
836  Dispose (true);
837  }
838 
839  protected virtual void Dispose (bool disposing)
840  {
841  if (!IsCompleted)
842  throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
843 
844  // Set action to null so that the GC can collect the delegate and thus
845  // any big object references that the user might have captured in a anonymous method
846  if (disposing) {
847  invoker = null;
848  state = null;
849  if (cancellationRegistration != null)
850  cancellationRegistration.Value.Dispose ();
851  }
852  }
853  #endregion
854 
855 #if NET_4_5
856  public
857 #else
858  internal
859 #endif
860  Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
861  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
862  {
863  if (continuationAction == null)
864  throw new ArgumentNullException ("continuationAction");
865  if (scheduler == null)
866  throw new ArgumentNullException ("scheduler");
867 
868  Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
869  state, cancellationToken,
870  GetCreationOptions (continuationOptions),
871  parent,
872  this);
873  ContinueWithCore (continuation, continuationOptions, scheduler);
874 
875  return continuation;
876  }
877 
878 #if NET_4_5
879 
880  public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
881  {
882  return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
883  }
884 
885  public Task ContinueWith (Action<Task, object> continuationAction, object state)
886  {
887  return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
888  }
889 
890  public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
891  {
892  return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
893  }
894 
895  public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
896  {
897  return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
898  }
899 
900  public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
901  {
902  return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
903  }
904 
905  public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
906  {
907  return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
908  }
909 
910  public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
911  {
912  return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
913  }
914 
915  public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
916  {
917  return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
918  }
919 
920  public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
921  {
922  return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
923  }
924 
925  public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
926  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
927  {
928  if (continuationFunction == null)
929  throw new ArgumentNullException ("continuationFunction");
930  if (scheduler == null)
931  throw new ArgumentNullException ("scheduler");
932 
933  var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
934  state,
935  cancellationToken,
936  GetCreationOptions (continuationOptions),
937  parent,
938  this);
939 
940  ContinueWithCore (t, continuationOptions, scheduler);
941 
942  return t;
943  }
944 
945  public static Task Delay (int millisecondsDelay)
946  {
947  return Delay (millisecondsDelay, CancellationToken.None);
948  }
949 
950  public static Task Delay (TimeSpan delay)
951  {
952  return Delay (CheckTimeout (delay), CancellationToken.None);
953  }
954 
955  public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
956  {
957  return Delay (CheckTimeout (delay), cancellationToken);
958  }
959 
960  public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
961  {
962  if (millisecondsDelay < -1)
963  throw new ArgumentOutOfRangeException ("millisecondsDelay");
964 
965  var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
966  task.SetupScheduler (TaskScheduler.Current);
967 
968  if (millisecondsDelay != Timeout.Infinite)
969  task.scheduler.QueueTask (task);
970 
971  return task;
972  }
973 
974  public static Task<TResult> FromResult<TResult> (TResult result)
975  {
976  var tcs = new TaskCompletionSource<TResult> ();
977  tcs.SetResult (result);
978  return tcs.Task;
979  }
980 
982  {
983  return new TaskAwaiter (this);
984  }
985 
986  public static Task Run (Action action)
987  {
988  return Run (action, CancellationToken.None);
989  }
990 
991  public static Task Run (Action action, CancellationToken cancellationToken)
992  {
993  if (cancellationToken.IsCancellationRequested)
994  return TaskConstants.Canceled;
995 
996  return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
997  }
998 
999  public static Task Run (Func<Task> function)
1000  {
1001  return Run (function, CancellationToken.None);
1002  }
1003 
1004  public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1005  {
1006  if (cancellationToken.IsCancellationRequested)
1007  return TaskConstants.Canceled;
1008 
1009  return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1010  }
1011 
1012  public static Task<TResult> Run<TResult> (Func<TResult> function)
1013  {
1014  return Run (function, CancellationToken.None);
1015  }
1016 
1017  public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1018  {
1019  if (cancellationToken.IsCancellationRequested)
1020  return TaskConstants<TResult>.Canceled;
1021 
1022  return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1023  }
1024 
1025  public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1026  {
1027  return Run (function, CancellationToken.None);
1028  }
1029 
1030  public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1031  {
1032  if (cancellationToken.IsCancellationRequested)
1033  return TaskConstants<TResult>.Canceled;
1034 
1035  return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1036  }
1037 
1038  public static Task WhenAll (params Task[] tasks)
1039  {
1040  if (tasks == null)
1041  throw new ArgumentNullException ("tasks");
1042 
1043  return WhenAllCore (tasks);
1044  }
1045 
1046  public static Task WhenAll (IEnumerable<Task> tasks)
1047  {
1048  if (tasks == null)
1049  throw new ArgumentNullException ("tasks");
1050 
1051  // Call ToList on input enumeration or we end up
1052  // enumerating it more than once
1053  return WhenAllCore (new List<Task> (tasks));
1054  }
1055 
1056  public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1057  {
1058  if (tasks == null)
1059  throw new ArgumentNullException ("tasks");
1060 
1061  return WhenAllCore<TResult> (tasks);
1062  }
1063 
1064  public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1065  {
1066  if (tasks == null)
1067  throw new ArgumentNullException ("tasks");
1068 
1069  // Call ToList on input enumeration or we end up
1070  // enumerating it more than once
1071  return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1072  }
1073 
1074  internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1075  {
1076  foreach (var t in tasks) {
1077  if (t == null)
1078  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1079  }
1080 
1081  var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1082  task.SetupScheduler (TaskScheduler.Current);
1083 
1084  var continuation = new WhenAllContinuation<TResult> (task, tasks);
1085  foreach (var t in tasks)
1086  t.ContinueWith (continuation);
1087 
1088  return task;
1089  }
1090 
1091  public static Task<Task> WhenAny (params Task[] tasks)
1092  {
1093  if (tasks == null)
1094  throw new ArgumentNullException ("tasks");
1095 
1096  return WhenAnyCore (tasks);
1097  }
1098 
1099  public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1100  {
1101  if (tasks == null)
1102  throw new ArgumentNullException ("tasks");
1103 
1104  return WhenAnyCore (new List<Task> (tasks));
1105  }
1106 
1107  public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1108  {
1109  if (tasks == null)
1110  throw new ArgumentNullException ("tasks");
1111 
1112  return WhenAnyCore<TResult> (tasks);
1113  }
1114 
1115  public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1116  {
1117  if (tasks == null)
1118  throw new ArgumentNullException ("tasks");
1119 
1120  return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1121  }
1122 
1123  static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1124  {
1125  if (tasks.Count == 0)
1126  throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1127 
1128  int completed_index = -1;
1129  for (int i = 0; i < tasks.Count; ++i) {
1130  var t = tasks[i];
1131  if (t == null)
1132  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1133 
1134  if (t.IsCompleted && completed_index < 0)
1135  completed_index = i;
1136  }
1137 
1138  var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1139 
1140  if (completed_index > 0) {
1141  task.TrySetResult (tasks[completed_index]);
1142  return task;
1143  }
1144 
1145  task.SetupScheduler (TaskScheduler.Current);
1146 
1147  var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1148  foreach (var t in tasks)
1149  t.ContinueWith (continuation);
1150 
1151  return task;
1152  }
1153 
1154  public static YieldAwaitable Yield ()
1155  {
1156  return new YieldAwaitable ();
1157  }
1158 #endif
1159 
1160  internal static Task WhenAllCore (IList<Task> tasks)
1161  {
1162  bool all_completed = true;
1163  foreach (var t in tasks) {
1164  if (t == null)
1165  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1166 
1167  all_completed &= t.Status == TaskStatus.RanToCompletion;
1168  }
1169 
1170  if (all_completed)
1171  return TaskConstants.Finished;
1172 
1173  var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1174  task.SetupScheduler (TaskScheduler.Current);
1175 
1176  var continuation = new WhenAllContinuation (task, tasks);
1177  foreach (var t in tasks)
1178  t.ContinueWith (continuation);
1179 
1180  return task;
1181  }
1182 
1183  internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1184  {
1185  if (tasks.Count == 0)
1186  throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1187 
1188  int completed_index = -1;
1189  for (int i = 0; i < tasks.Count; ++i) {
1190  var t = tasks [i];
1191  if (t == null)
1192  throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1193 
1194  if (t.IsCompleted && completed_index < 0)
1195  completed_index = i;
1196  }
1197 
1198  var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1199 
1200  if (completed_index > 0) {
1201  task.TrySetResult (tasks[completed_index]);
1202  return task;
1203  }
1204 
1205  task.SetupScheduler (TaskScheduler.Current);
1206 
1207  var continuation = new WhenAnyContinuation<Task> (task, tasks);
1208  foreach (var t in tasks)
1209  t.ContinueWith (continuation);
1210 
1211  return task;
1212  }
1213  #region Properties
1214 
1216  get {
1217  return token;
1218  }
1219  }
1220 
1221  public static TaskFactory Factory {
1222  get {
1223  return defaultFactory;
1224  }
1225  }
1226 
1227  public static int? CurrentId {
1228  get {
1229  Task t = current;
1230  return t == null ? (int?)null : t.Id;
1231  }
1232  }
1233 
1234  public AggregateException Exception {
1235  get {
1236  if (exSlot == null)
1237  return null;
1238  exSlot.Observed = true;
1239  return exSlot.Exception;
1240  }
1241  }
1242 
1243  public bool IsCanceled {
1244  get {
1245  return status == TaskStatus.Canceled;
1246  }
1247  }
1248 
1249  public bool IsCompleted {
1250  get {
1251  return status >= TaskStatus.RanToCompletion;
1252  }
1253  }
1254 
1255  public bool IsFaulted {
1256  get {
1257  return status == TaskStatus.Faulted;
1258  }
1259  }
1260 
1261  public TaskCreationOptions CreationOptions {
1262  get {
1263  return creationOptions & MaxTaskCreationOptions;
1264  }
1265  }
1266 
1267  public TaskStatus Status {
1268  get {
1269  return status;
1270  }
1271  internal set {
1272  status = value;
1273  Thread.MemoryBarrier ();
1274  }
1275  }
1276 
1277  TaskExceptionSlot ExceptionSlot {
1278  get {
1279  if (exSlot != null)
1280  return exSlot;
1281  AotInterlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1282  return exSlot;
1283  }
1284  }
1285 
1286  public object AsyncState {
1287  get {
1288  return state;
1289  }
1290  }
1291 
1292  bool IAsyncResult.CompletedSynchronously {
1293  get {
1294  return true;
1295  }
1296  }
1297 
1298  WaitHandle IAsyncResult.AsyncWaitHandle {
1299  get {
1300  return null;
1301  }
1302  }
1303 
1304  public int Id {
1305  get {
1306  return taskId;
1307  }
1308  }
1309 
1310  bool IsContinuation {
1311  get {
1312  return contAncestor != null;
1313  }
1314  }
1315 
1316  internal Task ContinuationAncestor {
1317  get {
1318  return contAncestor;
1319  }
1320  }
1321 
1322  internal string DisplayActionMethod {
1323  get {
1324  Delegate d = invoker.Action;
1325  return d == null ? "<none>" : d.Method.ToString ();
1326  }
1327  }
1328 
1329  #endregion
1330  }
1331 }
1332 #endif
static Task< Task > WhenAny(params Task[] tasks)
Definition: Task.cs:1091
bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
Definition: Task.cs:652
Task ContinueWith(Action< Task > continuationAction, TaskContinuationOptions continuationOptions)
Definition: Task.cs:252
static Task WhenAll(params Task[] tasks)
Definition: Task.cs:1038
static int WaitAny(Task[] tasks, TimeSpan timeout)
Definition: Task.cs:760
Task(Action< object > action, object state, TaskCreationOptions creationOptions)
Definition: Task.cs:120
static YieldAwaitable Yield()
Definition: Task.cs:1154
static Task< Task > WhenAny(IEnumerable< Task > tasks)
Definition: Task.cs:1099
void Start(TaskScheduler scheduler)
Definition: Task.cs:187
static Task Run(Func< Task > function)
Definition: Task.cs:999
static Task Delay(int millisecondsDelay)
Definition: Task.cs:945
static bool WaitAll(Task[] tasks, TimeSpan timeout)
Definition: Task.cs:697
void RunSynchronously(TaskScheduler scheduler)
Definition: Task.cs:213
static Task Delay(TimeSpan delay)
Definition: Task.cs:950
Task ContinueWith(Action< Task, object > continuationAction, object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
Definition: Task.cs:860
static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
Definition: Task.cs:707
Task(Action< object > action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
Definition: Task.cs:130
void SetAction(Action< object > action)
Definition: Task.cs:146
static int WaitAny(Task[] tasks, int millisecondsTimeout)
Definition: Task.cs:765
static Task Run(Func< Task > function, CancellationToken cancellationToken)
Definition: Task.cs:1004
Task ContinueWith(Action< Task, object > continuationAction, object state, TaskScheduler scheduler)
Definition: Task.cs:900
Task ContinueWith(Action< Task > continuationAction, TaskScheduler scheduler)
Definition: Task.cs:262
static void WaitAll(params Task[] tasks)
Definition: Task.cs:687
static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
Definition: Task.cs:960
TaskAwaiter GetAwaiter()
Definition: Task.cs:981
void SetAction(Action action)
Definition: Task.cs:141
Task ContinueWith(Action< Task, object > continuationAction, object state, TaskContinuationOptions continuationOptions)
Definition: Task.cs:895
Task(Action action)
Definition: Task.cs:88
Task(Action< object > action, object state, CancellationToken cancellationToken)
Definition: Task.cs:125
Task ContinueWith(Action< Task > continuationAction, CancellationToken cancellationToken)
Definition: Task.cs:257
Interlocked reference exchanges do not work with the older Mono AOT compiler so this type fudges arou...
void Wait(CancellationToken cancellationToken)
Definition: Task.cs:637
static Task Run(Action action, CancellationToken cancellationToken)
Definition: Task.cs:991
virtual void Dispose(bool disposing)
Definition: Task.cs:839
static Task Delay(TimeSpan delay, CancellationToken cancellationToken)
Definition: Task.cs:955
Task ContinueWith(Action< Task, object > continuationAction, object state)
Definition: Task.cs:885
Task ContinueWith(Action< Task > continuationAction)
Definition: Task.cs:247
ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
Definition: Task.cs:880
static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
Definition: Task.cs:775
static Task WhenAll(IEnumerable< Task > tasks)
Definition: Task.cs:1046
bool Wait(int millisecondsTimeout)
Definition: Task.cs:647
Task(Action action, CancellationToken cancellationToken)
Definition: Task.cs:100
static int WaitAny(params Task[] tasks)
Definition: Task.cs:755
bool Wait(TimeSpan timeout)
Definition: Task.cs:642
static void WaitAll(Task[] tasks, CancellationToken cancellationToken)
Definition: Task.cs:692
static bool WaitAll(Task[] tasks, int millisecondsTimeout)
Definition: Task.cs:702
Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
Definition: Task.cs:106
static Task Run(Action action)
Definition: Task.cs:986
Task ContinueWith(Action< Task, object > continuationAction, object state, CancellationToken cancellationToken)
Definition: Task.cs:890
Task(Action action, TaskCreationOptions creationOptions)
Definition: Task.cs:94
static Task Unwrap(Task< Task > task)
Task(Action< object > action, object state)
Definition: Task.cs:115
Task ContinueWith(Action< Task > continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
Definition: Task.cs:267
static int WaitAny(Task[] tasks, CancellationToken cancellationToken)
Definition: Task.cs:770
CancellationTokenRegistration Register(Action callback)