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;
45 const TaskCreationOptions FromAsyncOptionsNotSupported = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
48 : this (CancellationToken.None)
52 public TaskFactory (TaskScheduler scheduler)
53 : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler)
57 public TaskFactory (CancellationToken cancellationToken)
58 : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
62 public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
63 : this (CancellationToken.None, creationOptions, continuationOptions, null)
67 public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
69 this.cancellationToken = cancellationToken;
70 this.scheduler = scheduler;
71 this.creationOptions = creationOptions;
72 this.continuationOptions = continuationOptions;
74 TaskFactory.CheckContinuationOptions (continuationOptions);
76 this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
79 public TaskScheduler Scheduler {
85 public TaskContinuationOptions ContinuationOptions {
87 return continuationOptions;
91 public TaskCreationOptions CreationOptions {
93 return creationOptions;
97 public CancellationToken CancellationToken {
99 return cancellationToken;
103 #region StartNew for Task<TResult>
104 public Task<TResult> StartNew (Func<TResult> function)
106 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
109 public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
111 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
114 public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
116 return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
119 public Task<TResult> StartNew (Func<TResult> function,
120 CancellationToken cancellationToken,
121 TaskCreationOptions creationOptions,
122 TaskScheduler scheduler)
124 return StartNew ((o) => function (), null, cancellationToken, creationOptions, scheduler);
127 public Task<TResult> StartNew (Func<object, TResult> function, object state)
129 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
132 public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
134 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
137 public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
139 return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
142 public Task<TResult> StartNew (Func<object, TResult> function, object state,
143 CancellationToken cancellationToken,
144 TaskCreationOptions creationOptions,
145 TaskScheduler scheduler)
147 return parent.StartNew<TResult> (function, state, cancellationToken, creationOptions, scheduler);
153 public Task<TResult> ContinueWhenAny (Task[] tasks,
154 Func<Task, TResult> continuationFunction)
156 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
159 public Task<TResult> ContinueWhenAny (Task[] tasks,
160 Func<Task, TResult> continuationFunction,
161 CancellationToken cancellationToken)
163 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
166 public Task<TResult> ContinueWhenAny (Task[] tasks,
167 Func<Task, TResult> continuationFunction,
168 TaskContinuationOptions continuationOptions)
170 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
173 public Task<TResult> ContinueWhenAny (Task[] tasks,
174 Func<Task, TResult> continuationFunction,
175 CancellationToken cancellationToken,
176 TaskContinuationOptions continuationOptions,
177 TaskScheduler scheduler)
179 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
182 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
183 Func<Task<TAntecedentResult>, TResult> continuationFunction)
185 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
188 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
189 Func<Task<TAntecedentResult>, TResult> continuationFunction,
190 CancellationToken cancellationToken)
192 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
195 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
196 Func<Task<TAntecedentResult>, TResult> continuationFunction,
197 TaskContinuationOptions continuationOptions)
199 return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
202 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
203 Func<Task<TAntecedentResult>, TResult> continuationFunction,
204 CancellationToken cancellationToken,
205 TaskContinuationOptions continuationOptions,
206 TaskScheduler scheduler)
208 return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
211 public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
213 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
216 public Task<TResult> ContinueWhenAll (Task[] tasks,
217 Func<Task[], TResult> continuationFunction,
218 TaskContinuationOptions continuationOptions)
220 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
223 public Task<TResult> ContinueWhenAll (Task[] tasks,
224 Func<Task[], TResult> continuationFunction,
225 CancellationToken cancellationToken)
227 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
230 public Task<TResult> ContinueWhenAll (Task[] tasks,
231 Func<Task[], TResult> continuationFunction,
232 CancellationToken cancellationToken,
233 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
235 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
238 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
239 Func<Task<TAntecedentResult>[], TResult> continuationFunction)
241 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
244 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
245 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
246 TaskContinuationOptions continuationOptions)
248 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
251 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
252 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
253 CancellationToken cancellationToken)
255 return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
258 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
259 Func<Task<TAntecedentResult>[], TResult> continuationFunction,
260 CancellationToken cancellationToken,
261 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
263 return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
270 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
272 return FromAsync (asyncResult, endMethod, creationOptions);
275 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
277 return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
280 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
282 return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
285 internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
287 if (asyncResult == null)
288 throw new ArgumentNullException ("asyncResult");
290 if (endMethod == null)
291 throw new ArgumentNullException ("endMethod");
293 if (scheduler == null)
294 throw new ArgumentNullException ("scheduler");
296 if ((creationOptions & FromAsyncOptionsNotSupported) != 0)
297 throw new ArgumentOutOfRangeException ("creationOptions");
299 var source = new CancellationTokenSource ();
300 var task = new Task<TResult> (l => {
302 return endMethod (asyncResult);
303 } catch (OperationCanceledException) {
305 source.Token.ThrowIfCancellationRequested ();
307 return default (TResult);
308 }, null, source.Token, creationOptions);
310 // Take quick path for completed operations
311 if (asyncResult.IsCompleted) {
312 task.RunSynchronously (scheduler);
314 ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
315 (s, t) => task.RunSynchronously (scheduler),
316 null, Timeout.Infinite, true);
322 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
325 return FromAsync (beginMethod, endMethod, state, creationOptions);
328 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
329 object state, TaskCreationOptions creationOptions)
331 return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
334 internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
335 object state, TaskCreationOptions creationOptions)
337 if (beginMethod == null)
338 throw new ArgumentNullException ("beginMethod");
340 if (endMethod == null)
341 throw new ArgumentNullException ("endMethod");
343 if ((creationOptions & FromAsyncOptionsNotSupported) != 0)
344 throw new ArgumentOutOfRangeException ("creationOptions");
346 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
347 beginMethod (l => InnerInvoke (tcs, endMethod, l), state);
352 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
353 TArg1 arg1, object state)
355 return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
358 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
359 TArg1 arg1, object state, TaskCreationOptions creationOptions)
361 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
364 internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
365 Func<IAsyncResult, TResult> endMethod,
366 TArg1 arg1, object state, TaskCreationOptions creationOptions)
368 if (beginMethod == null)
369 throw new ArgumentNullException ("beginMethod");
371 if (endMethod == null)
372 throw new ArgumentNullException ("endMethod");
374 if ((creationOptions & FromAsyncOptionsNotSupported) != 0)
375 throw new ArgumentOutOfRangeException ("creationOptions");
377 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
378 beginMethod (arg1, l => InnerInvoke (tcs, endMethod, l), state);
383 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
384 TArg1 arg1, TArg2 arg2, object state)
386 return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
389 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
390 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
392 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
395 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
396 TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
398 if (beginMethod == null)
399 throw new ArgumentNullException ("beginMethod");
401 if (endMethod == null)
402 throw new ArgumentNullException ("endMethod");
404 if ((creationOptions & FromAsyncOptionsNotSupported) != 0)
405 throw new ArgumentOutOfRangeException ("creationOptions");
407 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
408 beginMethod (arg1, arg2, l => InnerInvoke (tcs, endMethod, l), state);
413 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
414 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
416 return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
419 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
420 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
421 TaskCreationOptions creationOptions)
423 return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
426 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
427 TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
429 if (beginMethod == null)
430 throw new ArgumentNullException ("beginMethod");
432 if (endMethod == null)
433 throw new ArgumentNullException ("endMethod");
435 if ((creationOptions & FromAsyncOptionsNotSupported) != 0)
436 throw new ArgumentOutOfRangeException ("creationOptions");
438 var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
439 beginMethod (arg1, arg2, arg3, l => InnerInvoke (tcs, endMethod, l), state);
446 TaskScheduler GetScheduler ()
448 return scheduler ?? TaskScheduler.Current;
451 static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
454 tcs.SetResult (endMethod (l));
455 } catch (OperationCanceledException) {
457 } catch (Exception e) {
458 tcs.SetException (e);