TaskFactory_T.cs
Go to the documentation of this file.
1 //
2 // TaskFactory_T.cs
3 //
4 // Authors:
5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // Marek Safar <marek.safar@gmail.com>
7 //
8 // Copyright (c) 2009 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 #if NET_4_0
30 
31 namespace System.Threading.Tasks
32 {
33  public class TaskFactory<TResult>
34  {
35  readonly TaskScheduler scheduler;
36  TaskCreationOptions creationOptions;
37  TaskContinuationOptions continuationOptions;
38  CancellationToken cancellationToken;
39 
40  TaskFactory parent;
41 
42  public TaskFactory ()
43  : this (CancellationToken.None)
44  {
45  }
46 
47  public TaskFactory (TaskScheduler scheduler)
48  : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler)
49  {
50  }
51 
52  public TaskFactory (CancellationToken cancellationToken)
53  : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
54  {
55  }
56 
57  public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
58  : this (CancellationToken.None, creationOptions, continuationOptions, null)
59  {
60  }
61 
62  public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
63  {
64  this.cancellationToken = cancellationToken;
65  this.scheduler = scheduler;
66  this.creationOptions = creationOptions;
67  this.continuationOptions = continuationOptions;
68 
69  TaskFactory.CheckContinuationOptions (continuationOptions);
70 
71  this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
72  }
73 
74  public TaskScheduler Scheduler {
75  get {
76  return scheduler;
77  }
78  }
79 
80  public TaskContinuationOptions ContinuationOptions {
81  get {
82  return continuationOptions;
83  }
84  }
85 
86  public TaskCreationOptions CreationOptions {
87  get {
88  return creationOptions;
89  }
90  }
91 
93  get {
94  return cancellationToken;
95  }
96  }
97 
98  #region StartNew for Task<TResult>
99  public Task<TResult> StartNew (Func<TResult> function)
100  {
101  return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
102  }
103 
104  public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
105  {
106  return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
107  }
108 
109  public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
110  {
111  return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
112  }
113 
114  public Task<TResult> StartNew (Func<TResult> function,
115  CancellationToken cancellationToken,
116  TaskCreationOptions creationOptions,
117  TaskScheduler scheduler)
118  {
119  return StartNew ((o) => function (), null, cancellationToken, creationOptions, scheduler);
120  }
121 
122  public Task<TResult> StartNew (Func<object, TResult> function, object state)
123  {
124  return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
125  }
126 
127  public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
128  {
129  return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
130  }
131 
132  public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
133  {
134  return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
135  }
136 
137  public Task<TResult> StartNew (Func<object, TResult> function, object state,
138  CancellationToken cancellationToken,
139  TaskCreationOptions creationOptions,
140  TaskScheduler scheduler)
141  {
142  return parent.StartNew<TResult> (function, state, cancellationToken, creationOptions, scheduler);
143  }
144  #endregion
145 
146  #region Continue
147 
149  Func<Task, TResult> continuationFunction)
150  {
151  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
152  }
153 
155  Func<Task, TResult> continuationFunction,
156  CancellationToken cancellationToken)
157  {
158  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
159  }
160 
162  Func<Task, TResult> continuationFunction,
163  TaskContinuationOptions continuationOptions)
164  {
165  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
166  }
167 
169  Func<Task, TResult> continuationFunction,
170  CancellationToken cancellationToken,
171  TaskContinuationOptions continuationOptions,
172  TaskScheduler scheduler)
173  {
174  return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
175  }
176 
177  public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
178  Func<Task<TAntecedentResult>, TResult> continuationFunction)
179  {
180  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
181  }
182 
183  public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
184  Func<Task<TAntecedentResult>, TResult> continuationFunction,
185  CancellationToken cancellationToken)
186  {
187  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
188  }
189 
190  public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
191  Func<Task<TAntecedentResult>, TResult> continuationFunction,
192  TaskContinuationOptions continuationOptions)
193  {
194  return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
195  }
196 
197  public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
198  Func<Task<TAntecedentResult>, TResult> continuationFunction,
199  CancellationToken cancellationToken,
200  TaskContinuationOptions continuationOptions,
201  TaskScheduler scheduler)
202  {
203  return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
204  }
205 
206  public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
207  {
208  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
209  }
210 
212  Func<Task[], TResult> continuationFunction,
213  TaskContinuationOptions continuationOptions)
214  {
215  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
216  }
217 
219  Func<Task[], TResult> continuationFunction,
220  CancellationToken cancellationToken)
221  {
222  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
223  }
224 
226  Func<Task[], TResult> continuationFunction,
227  CancellationToken cancellationToken,
228  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
229  {
230  return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
231  }
232 
233  public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
234  Func<Task<TAntecedentResult>[], TResult> continuationFunction)
235  {
236  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
237  }
238 
239  public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
240  Func<Task<TAntecedentResult>[], TResult> continuationFunction,
241  TaskContinuationOptions continuationOptions)
242  {
243  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
244  }
245 
246  public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
247  Func<Task<TAntecedentResult>[], TResult> continuationFunction,
248  CancellationToken cancellationToken)
249  {
250  return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
251  }
252 
253  public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
254  Func<Task<TAntecedentResult>[], TResult> continuationFunction,
255  CancellationToken cancellationToken,
256  TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
257  {
258  return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
259  }
260 
261  #endregion
262 
263  #region FromAsync
264 
265  public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
266  {
267  return FromAsync (asyncResult, endMethod, creationOptions);
268  }
269 
270  public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
271  {
272  return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
273  }
274 
275  public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
276  {
277  return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
278  }
279 
280  internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
281  {
282  if (asyncResult == null)
283  throw new ArgumentNullException ("asyncResult");
284 
285  if (endMethod == null)
286  throw new ArgumentNullException ("endMethod");
287 
288  if (scheduler == null)
289  throw new ArgumentNullException ("scheduler");
290 
291  if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
292  throw new ArgumentOutOfRangeException ("creationOptions");
293 
294  var source = new CancellationTokenSource ();
295  var task = new Task<TResult> (l => {
296  try {
297  return endMethod (asyncResult);
298  } catch (OperationCanceledException) {
299  source.Cancel ();
300  source.Token.ThrowIfCancellationRequested ();
301  }
302  return default (TResult);
303  }, null, source.Token, creationOptions);
304 
305  // Take quick path for completed operations
306  if (asyncResult.IsCompleted) {
307  task.RunSynchronously (scheduler);
308  } else {
309  ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
310  (s, t) => task.RunSynchronously (scheduler),
311  null, Timeout.Infinite, true);
312  }
313 
314  return task;
315  }
316 
317  public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
318  object state)
319  {
320  return FromAsync (beginMethod, endMethod, state, creationOptions);
321  }
322 
323  public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
324  object state, TaskCreationOptions creationOptions)
325  {
326  return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
327  }
328 
329  internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
330  object state, TaskCreationOptions creationOptions)
331  {
332  if (beginMethod == null)
333  throw new ArgumentNullException ("beginMethod");
334 
335  if (endMethod == null)
336  throw new ArgumentNullException ("endMethod");
337 
338  if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
339  throw new ArgumentOutOfRangeException ("creationOptions");
340 
341  var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
342  var alreadyInvoked = new AtomicBoolean ();
343  var iar = beginMethod (l => {
344  if (alreadyInvoked.TryRelaxedSet ())
345  InnerInvoke (tcs, endMethod, l);
346  }, state);
347  if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
348  InnerInvoke (tcs, endMethod, iar);
349 
350  return tcs.Task;
351  }
352 
353  public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
354  TArg1 arg1, object state)
355  {
356  return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
357  }
358 
359  public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
360  TArg1 arg1, object state, TaskCreationOptions creationOptions)
361  {
362  return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
363  }
364 
365  internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
366  Func<IAsyncResult, TResult> endMethod,
367  TArg1 arg1, object state, TaskCreationOptions creationOptions)
368  {
369  if (beginMethod == null)
370  throw new ArgumentNullException ("beginMethod");
371 
372  if (endMethod == null)
373  throw new ArgumentNullException ("endMethod");
374 
375  if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
376  throw new ArgumentOutOfRangeException ("creationOptions");
377 
378  var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
379  var alreadyInvoked = new AtomicBoolean ();
380  var iar = beginMethod (arg1, l => {
381  if (alreadyInvoked.TryRelaxedSet ())
382  InnerInvoke (tcs, endMethod, l);
383  }, state);
384  if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
385  InnerInvoke (tcs, endMethod, iar);
386 
387  return tcs.Task;
388  }
389 
390  public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
391  TArg1 arg1, TArg2 arg2, object state)
392  {
393  return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
394  }
395 
396  public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
397  TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
398  {
399  return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
400  }
401 
402  internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
403  TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
404  {
405  if (beginMethod == null)
406  throw new ArgumentNullException ("beginMethod");
407 
408  if (endMethod == null)
409  throw new ArgumentNullException ("endMethod");
410 
411  if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
412  throw new ArgumentOutOfRangeException ("creationOptions");
413 
414  var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
415  var alreadyInvoked = new AtomicBoolean ();
416  var iar = beginMethod (arg1, arg2, l => {
417  if (alreadyInvoked.TryRelaxedSet ())
418  InnerInvoke (tcs, endMethod, l);
419  }, state);
420  if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
421  InnerInvoke (tcs, endMethod, iar);
422 
423  return tcs.Task;
424  }
425 
426  public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
427  TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
428  {
429  return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
430  }
431 
432  public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
433  TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
434  TaskCreationOptions creationOptions)
435  {
436  return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
437  }
438 
439  internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
440  TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
441  {
442  if (beginMethod == null)
443  throw new ArgumentNullException ("beginMethod");
444 
445  if (endMethod == null)
446  throw new ArgumentNullException ("endMethod");
447 
448  if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
449  throw new ArgumentOutOfRangeException ("creationOptions");
450 
451  var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
452  var alreadyInvoked = new AtomicBoolean ();
453  var iar = beginMethod (arg1, arg2, arg3, l => {
454  if (alreadyInvoked.TryRelaxedSet ())
455  InnerInvoke (tcs, endMethod, l);
456  }, state);
457  if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
458  InnerInvoke (tcs, endMethod, iar);
459 
460  return tcs.Task;
461  }
462 
463  #endregion
464 
465  TaskScheduler GetScheduler ()
466  {
467  return scheduler ?? TaskScheduler.Current;
468  }
469 
470  static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
471  {
472  try {
473  tcs.SetResult (endMethod (l));
474  } catch (OperationCanceledException) {
475  tcs.SetCanceled ();
476  } catch (Exception e) {
477  tcs.SetException (e);
478  }
479  }
480  }
481 }
482 #endif
Task< TResult > ContinueWhenAll(Task[] tasks, Func< Task[], TResult > continuationFunction, TaskContinuationOptions continuationOptions)
TaskFactory(TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
Task< TResult > ContinueWhenAny(Task[] tasks, Func< Task, TResult > continuationFunction, CancellationToken cancellationToken)
Task< TResult > StartNew(Func< TResult > function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
Task< TResult > ContinueWhenAny(Task[] tasks, Func< Task, TResult > continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
Task< TResult > StartNew(Func< object, TResult > function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
Task< TResult > StartNew(Func< TResult > function, TaskCreationOptions creationOptions)
Task< TResult > ContinueWhenAll(Task[] tasks, Func< Task[], TResult > continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
TaskFactory(TaskScheduler scheduler)
Task< TResult > StartNew(Func< object, TResult > function, object state, TaskCreationOptions creationOptions)
Task< TResult > FromAsync(IAsyncResult asyncResult, Func< IAsyncResult, TResult > endMethod, TaskCreationOptions creationOptions)
Task< TResult > StartNew(Func< TResult > function)
TaskFactory(CancellationToken cancellationToken)
Task< TResult > ContinueWhenAny(Task[] tasks, Func< Task, TResult > continuationFunction)
Task< TResult > ContinueWhenAny(Task[] tasks, Func< Task, TResult > continuationFunction, TaskContinuationOptions continuationOptions)
Task< TResult > StartNew(Func< object, TResult > function, object state)
Task< TResult > FromAsync(IAsyncResult asyncResult, Func< IAsyncResult, TResult > endMethod)
Task< TResult > ContinueWhenAll(Task[] tasks, Func< Task[], TResult > continuationFunction)
Task< TResult > StartNew(Func< TResult > function, CancellationToken cancellationToken)
Task< TResult > FromAsync(Func< AsyncCallback, object, IAsyncResult > beginMethod, Func< IAsyncResult, TResult > endMethod, object state, TaskCreationOptions creationOptions)
Task< TResult > ContinueWhenAll(Task[] tasks, Func< Task[], TResult > continuationFunction, CancellationToken cancellationToken)
Task< TResult > FromAsync(IAsyncResult asyncResult, Func< IAsyncResult, TResult > endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
Task< TResult > FromAsync(Func< AsyncCallback, object, IAsyncResult > beginMethod, Func< IAsyncResult, TResult > endMethod, object state)
Task< TResult > StartNew(Func< object, TResult > function, object state, CancellationToken cancellationToken)