5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // Marek Safar <marek.safar@gmail.com>
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 using System.Threading;
34 namespace System.Threading.Tasks
36 public class TaskFactory<TResult>
38 readonly TaskScheduler scheduler;
39 TaskCreationOptions creationOptions;
40 TaskContinuationOptions continuationOptions;
41 CancellationToken cancellationToken;
46 : this (CancellationToken.None)
50 public TaskFactory (TaskScheduler scheduler)
51 : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler)
55 public TaskFactory (CancellationToken cancellationToken)
56 : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
60 public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
61 : this (CancellationToken.None, creationOptions, continuationOptions, null)
65 public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
67 this.cancellationToken = cancellationToken;
68 this.scheduler = scheduler;
69 this.creationOptions = creationOptions;
70 this.continuationOptions = continuationOptions;
72 TaskFactory.CheckContinuationOptions (continuationOptions);
74 this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
77 public TaskScheduler Scheduler {
83 public TaskContinuationOptions ContinuationOptions {
85 return continuationOptions;
89 public TaskCreationOptions CreationOptions {
91 return creationOptions;
95 public CancellationToken CancellationToken {
97 return cancellationToken;
101 #region StartNew for Task<TResult>
102 public Task<TResult> StartNew (Func<TResult> function)
104 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
107 public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
109 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
112 public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
114 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
117 public Task<TResult> StartNew (Func<TResult> function,
118 CancellationToken cancellationToken,
119 TaskCreationOptions creationOptions,
120 TaskScheduler scheduler)
122 return StartNew ((o) => function (), null, cancellationToken, creationOptions, scheduler);
125 public Task<TResult> StartNew (Func<object, TResult> function, object state)
127 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
130 public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
132 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
135 public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
137 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
140 public Task<TResult> StartNew (Func<object, TResult> function, object state,
141 CancellationToken cancellationToken,
142 TaskCreationOptions creationOptions,
143 TaskScheduler scheduler)
145 return parent.StartNew<TResult> (function, state, cancellationToken, creationOptions, scheduler);
151 public Task<TResult> ContinueWhenAny (Task[] tasks,
152 Func<Task, TResult> continuationFunction)
154 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
157 public Task<TResult> ContinueWhenAny (Task[] tasks,
158 Func<Task, TResult> continuationFunction,
159 CancellationToken cancellationToken)
161 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
164 public Task<TResult> ContinueWhenAny (Task[] tasks,
165 Func<Task, TResult> continuationFunction,
166 TaskContinuationOptions continuationOptions)
168 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
171 public Task<TResult> ContinueWhenAny (Task[] tasks,
172 Func<Task, TResult> continuationFunction,
173 CancellationToken cancellationToken,
174 TaskContinuationOptions continuationOptions,
175 TaskScheduler scheduler)
177 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
180 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
181 Func<Task<TAntecedentResult>, TResult> continuationFunction)
183 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
186 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
187 Func<Task<TAntecedentResult>, TResult> continuationFunction,
188 CancellationToken cancellationToken)
190 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
193 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
194 Func<Task<TAntecedentResult>, TResult> continuationFunction,
195 TaskContinuationOptions continuationOptions)
197 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
200 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
201 Func<Task<TAntecedentResult>, TResult> continuationFunction,
202 CancellationToken cancellationToken,
203 TaskContinuationOptions continuationOptions,
204 TaskScheduler scheduler)
206 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
209 public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
211 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
214 public Task<TResult> ContinueWhenAll (Task[] tasks,
215 Func<Task[], TResult> continuationFunction,
216 TaskContinuationOptions continuationOptions)
218 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
221 public Task<TResult> ContinueWhenAll (Task[] tasks,
222 Func<Task[], TResult> continuationFunction,
223 CancellationToken cancellationToken)
225 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
228 public Task<TResult> ContinueWhenAll (Task[] tasks,
229 Func<Task[], TResult> continuationFunction,
230 CancellationToken cancellationToken,
231 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
233 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
236 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
237 Func<Task<TAntecedentResult>[], TResult> continuationFunction)
239 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
242 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
243 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
244 TaskContinuationOptions continuationOptions)
246 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
249 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
250 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
251 CancellationToken cancellationToken)
253 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
256 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
257 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
258 CancellationToken cancellationToken,
259 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
261 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
268 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
270 return FromAsync (asyncResult, endMethod, creationOptions);
273 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
275 return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
278 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
280 return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
283 internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
285 if (asyncResult == null)
286 throw new ArgumentNullException ("asyncResult");
288 if (endMethod == null)
289 throw new ArgumentNullException ("endMethod");
291 if (scheduler == null)
292 throw new ArgumentNullException ("scheduler");
294 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
295 throw new ArgumentOutOfRangeException ("creationOptions");
297 var source = new CancellationTokenSource ();
298 var task = new Task<TResult> (l => {
300 return endMethod (asyncResult);
301 } catch (OperationCanceledException) {
303 source.Token.ThrowIfCancellationRequested ();
305 return default (TResult);
306 }, null, source.Token, creationOptions);
308 // Take quick path for completed operations
309 if (asyncResult.IsCompleted) {
310 task.RunSynchronously (scheduler);
312 ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
313 (s, t) => task.RunSynchronously (scheduler),
314 null, Timeout.Infinite, true);
320 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
323 return FromAsync (beginMethod, endMethod, state, creationOptions);
326 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
327 object state, TaskCreationOptions creationOptions)
329 return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
332 internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
333 object state, TaskCreationOptions creationOptions)
335 if (beginMethod == null)
336 throw new ArgumentNullException ("beginMethod");
338 if (endMethod == null)
339 throw new ArgumentNullException ("endMethod");
341 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
342 throw new ArgumentOutOfRangeException ("creationOptions");
344 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
345 beginMethod (l => InnerInvoke (tcs, endMethod, l), state);
350 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
351 TArg1 arg1, object state)
353 return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
356 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
357 TArg1 arg1, object state, TaskCreationOptions creationOptions)
359 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
362 internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
363 Func<IAsyncResult, TResult> endMethod,
364 TArg1 arg1, object state, TaskCreationOptions creationOptions)
366 if (beginMethod == null)
367 throw new ArgumentNullException ("beginMethod");
369 if (endMethod == null)
370 throw new ArgumentNullException ("endMethod");
372 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
373 throw new ArgumentOutOfRangeException ("creationOptions");
375 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
376 beginMethod (arg1, l => InnerInvoke (tcs, endMethod, l), state);
381 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
382 TArg1 arg1, TArg2 arg2, object state)
384 return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
387 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
388 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
390 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
393 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
394 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
396 if (beginMethod == null)
397 throw new ArgumentNullException ("beginMethod");
399 if (endMethod == null)
400 throw new ArgumentNullException ("endMethod");
402 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
403 throw new ArgumentOutOfRangeException ("creationOptions");
405 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
406 beginMethod (arg1, arg2, l => InnerInvoke (tcs, endMethod, l), state);
411 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
412 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
414 return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
417 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
418 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
419 TaskCreationOptions creationOptions)
421 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
424 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
425 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
427 if (beginMethod == null)
428 throw new ArgumentNullException ("beginMethod");
430 if (endMethod == null)
431 throw new ArgumentNullException ("endMethod");
433 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
434 throw new ArgumentOutOfRangeException ("creationOptions");
436 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
437 beginMethod (arg1, arg2, arg3, l => InnerInvoke (tcs, endMethod, l), state);
444 TaskScheduler GetScheduler ()
446 return scheduler ?? TaskScheduler.Current;
449 static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
452 tcs.SetResult (endMethod (l));
453 } catch (OperationCanceledException) {
455 } catch (Exception e) {
456 tcs.SetException (e);