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
31 namespace System.Threading.Tasks
33 public class TaskFactory<TResult>
35 readonly TaskScheduler scheduler;
36 TaskCreationOptions creationOptions;
37 TaskContinuationOptions continuationOptions;
38 CancellationToken cancellationToken;
43 : this (CancellationToken.None)
47 public TaskFactory (TaskScheduler scheduler)
48 : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler)
52 public TaskFactory (CancellationToken cancellationToken)
53 : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
57 public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
58 : this (CancellationToken.None, creationOptions, continuationOptions, null)
62 public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
64 this.cancellationToken = cancellationToken;
65 this.scheduler = scheduler;
66 this.creationOptions = creationOptions;
67 this.continuationOptions = continuationOptions;
69 TaskFactory.CheckContinuationOptions (continuationOptions);
71 this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
74 public TaskScheduler Scheduler {
80 public TaskContinuationOptions ContinuationOptions {
82 return continuationOptions;
86 public TaskCreationOptions CreationOptions {
88 return creationOptions;
92 public CancellationToken CancellationToken {
94 return cancellationToken;
98 #region StartNew for Task<TResult>
99 public Task<TResult> StartNew (Func<TResult> function)
101 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
104 public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
106 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
109 public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
111 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
114 public Task<TResult> StartNew (Func<TResult> function,
115 CancellationToken cancellationToken,
116 TaskCreationOptions creationOptions,
117 TaskScheduler scheduler)
119 return StartNew ((o) => function (), null, cancellationToken, creationOptions, scheduler);
122 public Task<TResult> StartNew (Func<object, TResult> function, object state)
124 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
127 public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
129 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
132 public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
134 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
137 public Task<TResult> StartNew (Func<object, TResult> function, object state,
138 CancellationToken cancellationToken,
139 TaskCreationOptions creationOptions,
140 TaskScheduler scheduler)
142 return parent.StartNew<TResult> (function, state, cancellationToken, creationOptions, scheduler);
148 public Task<TResult> ContinueWhenAny (Task[] tasks,
149 Func<Task, TResult> continuationFunction)
151 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
154 public Task<TResult> ContinueWhenAny (Task[] tasks,
155 Func<Task, TResult> continuationFunction,
156 CancellationToken cancellationToken)
158 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
161 public Task<TResult> ContinueWhenAny (Task[] tasks,
162 Func<Task, TResult> continuationFunction,
163 TaskContinuationOptions continuationOptions)
165 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
168 public Task<TResult> ContinueWhenAny (Task[] tasks,
169 Func<Task, TResult> continuationFunction,
170 CancellationToken cancellationToken,
171 TaskContinuationOptions continuationOptions,
172 TaskScheduler scheduler)
174 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
177 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
178 Func<Task<TAntecedentResult>, TResult> continuationFunction)
180 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
183 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
184 Func<Task<TAntecedentResult>, TResult> continuationFunction,
185 CancellationToken cancellationToken)
187 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
190 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
191 Func<Task<TAntecedentResult>, TResult> continuationFunction,
192 TaskContinuationOptions continuationOptions)
194 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
197 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
198 Func<Task<TAntecedentResult>, TResult> continuationFunction,
199 CancellationToken cancellationToken,
200 TaskContinuationOptions continuationOptions,
201 TaskScheduler scheduler)
203 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
206 public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
208 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
211 public Task<TResult> ContinueWhenAll (Task[] tasks,
212 Func<Task[], TResult> continuationFunction,
213 TaskContinuationOptions continuationOptions)
215 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
218 public Task<TResult> ContinueWhenAll (Task[] tasks,
219 Func<Task[], TResult> continuationFunction,
220 CancellationToken cancellationToken)
222 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
225 public Task<TResult> ContinueWhenAll (Task[] tasks,
226 Func<Task[], TResult> continuationFunction,
227 CancellationToken cancellationToken,
228 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
230 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
233 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
234 Func<Task<TAntecedentResult>[], TResult> continuationFunction)
236 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
239 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
240 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
241 TaskContinuationOptions continuationOptions)
243 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
246 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
247 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
248 CancellationToken cancellationToken)
250 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
253 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
254 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
255 CancellationToken cancellationToken,
256 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
258 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
265 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
267 return FromAsync (asyncResult, endMethod, creationOptions);
270 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
272 return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
275 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
277 return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
280 internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
282 if (asyncResult == null)
283 throw new ArgumentNullException ("asyncResult");
285 if (endMethod == null)
286 throw new ArgumentNullException ("endMethod");
288 if (scheduler == null)
289 throw new ArgumentNullException ("scheduler");
291 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
292 throw new ArgumentOutOfRangeException ("creationOptions");
294 var source = new CancellationTokenSource ();
295 var task = new Task<TResult> (l => {
297 return endMethod (asyncResult);
298 } catch (OperationCanceledException) {
300 source.Token.ThrowIfCancellationRequested ();
302 return default (TResult);
303 }, null, source.Token, creationOptions);
305 // Take quick path for completed operations
306 if (asyncResult.IsCompleted) {
307 task.RunSynchronously (scheduler);
309 ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
310 (s, t) => task.RunSynchronously (scheduler),
311 null, Timeout.Infinite, true);
317 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
320 return FromAsync (beginMethod, endMethod, state, creationOptions);
323 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
324 object state, TaskCreationOptions creationOptions)
326 return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
329 internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
330 object state, TaskCreationOptions creationOptions)
332 if (beginMethod == null)
333 throw new ArgumentNullException ("beginMethod");
335 if (endMethod == null)
336 throw new ArgumentNullException ("endMethod");
338 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
339 throw new ArgumentOutOfRangeException ("creationOptions");
341 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
342 var alreadyInvoked = false;
343 var iar = beginMethod (l => {
344 alreadyInvoked = true;
345 InnerInvoke (tcs, endMethod, l);
347 if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
348 InnerInvoke (tcs, endMethod, iar);
354 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
355 TArg1 arg1, object state)
357 return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
360 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
361 TArg1 arg1, object state, TaskCreationOptions creationOptions)
363 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
366 internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
367 Func<IAsyncResult, TResult> endMethod,
368 TArg1 arg1, object state, TaskCreationOptions creationOptions)
370 if (beginMethod == null)
371 throw new ArgumentNullException ("beginMethod");
373 if (endMethod == null)
374 throw new ArgumentNullException ("endMethod");
376 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
377 throw new ArgumentOutOfRangeException ("creationOptions");
379 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
380 var alreadyInvoked = false;
381 var iar = beginMethod (arg1, l => {
382 alreadyInvoked = true;
383 InnerInvoke (tcs, endMethod, l);
385 if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
386 InnerInvoke (tcs, endMethod, iar);
392 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
393 TArg1 arg1, TArg2 arg2, object state)
395 return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
398 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
399 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
401 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
404 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
405 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
407 if (beginMethod == null)
408 throw new ArgumentNullException ("beginMethod");
410 if (endMethod == null)
411 throw new ArgumentNullException ("endMethod");
413 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
414 throw new ArgumentOutOfRangeException ("creationOptions");
416 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
417 var alreadyInvoked = false;
418 var iar = beginMethod (arg1, arg2, l => {
419 alreadyInvoked = true;
420 InnerInvoke (tcs, endMethod, l);
422 if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
423 InnerInvoke (tcs, endMethod, iar);
429 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
430 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
432 return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
435 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
436 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
437 TaskCreationOptions creationOptions)
439 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
442 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
443 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
445 if (beginMethod == null)
446 throw new ArgumentNullException ("beginMethod");
448 if (endMethod == null)
449 throw new ArgumentNullException ("endMethod");
451 if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
452 throw new ArgumentOutOfRangeException ("creationOptions");
454 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
455 bool alreadyInvoked = false;
456 var iar = beginMethod (arg1, arg2, arg3, l => {
457 alreadyInvoked = true;
458 InnerInvoke (tcs, endMethod, l);
460 if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
461 InnerInvoke (tcs, endMethod, iar);
469 TaskScheduler GetScheduler ()
471 return scheduler ?? TaskScheduler.Current;
474 static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
477 tcs.SetResult (endMethod (l));
478 } catch (OperationCanceledException) {
480 } catch (Exception e) {
481 tcs.SetException (e);