All files
[pithos-ms-client] / trunk / Libraries / ParallelExtensionsExtras / Extensions / TaskFactoryExtensions / TaskFactoryExtensions_Delayed.cs
1 //--------------------------------------------------------------------------
2 // 
3 //  Copyright (c) Microsoft Corporation.  All rights reserved. 
4 // 
5 //  File: TaskFactoryExtensions_Delayed.cs
6 //
7 //--------------------------------------------------------------------------
8
9 namespace System.Threading.Tasks
10 {
11     public static partial class TaskFactoryExtensions
12     {
13         #region TaskFactory No Action
14         /// <summary>Creates a Task that will complete after the specified delay.</summary>
15         /// <param name="factory">The TaskFactory.</param>
16         /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
17         /// <returns>A Task that will be completed after the specified duration.</returns>
18         public static Task StartNewDelayed(
19             this TaskFactory factory, int millisecondsDelay)
20         {
21             return StartNewDelayed(factory, millisecondsDelay, CancellationToken.None);
22         }
23
24         /// <summary>Creates a Task that will complete after the specified delay.</summary>
25         /// <param name="factory">The TaskFactory.</param>
26         /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
27         /// <param name="cancellationToken">The cancellation token that can be used to cancel the timed task.</param>
28         /// <returns>A Task that will be completed after the specified duration and that's cancelable with the specified token.</returns>
29         public static Task StartNewDelayed(this TaskFactory factory, int millisecondsDelay, CancellationToken cancellationToken)
30         {
31             // Validate arguments
32             if (factory == null) throw new ArgumentNullException("factory");
33             if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
34
35             // Create the timed task
36             var tcs = new TaskCompletionSource<object>(factory.CreationOptions);
37             var ctr = default(CancellationTokenRegistration);
38
39             // Create the timer but don't start it yet.  If we start it now,
40             // it might fire before ctr has been set to the right registration.
41             var timer = new Timer(self =>
42             {
43                 // Clean up both the cancellation token and the timer, and try to transition to completed
44                 ctr.Dispose();
45                 ((Timer)self).Dispose();
46                 tcs.TrySetResult(null);
47             });
48
49             // Register with the cancellation token.
50             if (cancellationToken.CanBeCanceled)
51             {
52                 // When cancellation occurs, cancel the timer and try to transition to canceled.
53                 // There could be a race, but it's benign.
54                 ctr = cancellationToken.Register(() =>
55                 {
56                     timer.Dispose();
57                     tcs.TrySetCanceled();
58                 });
59             }
60
61             // Start the timer and hand back the task...
62             timer.Change(millisecondsDelay, Timeout.Infinite);
63             return tcs.Task;
64         }
65         #endregion
66
67         #region TaskFactory with Action
68         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
69         /// <param name="factory">The factory to use to create the task.</param>
70         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
71         /// <param name="action">The delegate executed by the task.</param>
72         /// <returns>The created Task.</returns>
73         public static Task StartNewDelayed(
74             this TaskFactory factory,
75             int millisecondsDelay, Action action)
76         {
77             if (factory == null) throw new ArgumentNullException("factory");
78             return StartNewDelayed(factory, millisecondsDelay, action, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
79         }
80
81         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
82         /// <param name="factory">The factory to use to create the task.</param>
83         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
84         /// <param name="action">The delegate executed by the task.</param>
85         /// <param name="creationOptions">Options that control the task's behavior.</param>
86         /// <returns>The created Task.</returns>
87         public static Task StartNewDelayed(
88             this TaskFactory factory,
89             int millisecondsDelay, Action action,
90             TaskCreationOptions creationOptions)
91         {
92             if (factory == null) throw new ArgumentNullException("factory");
93             return StartNewDelayed(factory, millisecondsDelay, action, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
94         }
95
96         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
97         /// <param name="factory">The factory to use to create the task.</param>
98         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
99         /// <param name="action">The delegate executed by the task.</param>
100         /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
101         /// <returns>The created Task.</returns>
102         public static Task StartNewDelayed(
103             this TaskFactory factory,
104             int millisecondsDelay, Action action,
105             CancellationToken cancellationToken)
106         {
107             if (factory == null) throw new ArgumentNullException("factory");
108             return StartNewDelayed(factory, millisecondsDelay, action, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
109         }
110
111         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
112         /// <param name="factory">The factory to use to create the task.</param>
113         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
114         /// <param name="action">The delegate executed by the task.</param>
115         /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
116         /// <param name="creationOptions">Options that control the task's behavior.</param>
117         /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
118         /// <returns>The created Task.</returns>
119         public static Task StartNewDelayed(
120             this TaskFactory factory,
121             int millisecondsDelay, Action action, 
122             CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
123         {
124             if (factory == null) throw new ArgumentNullException("factory");
125             if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
126             if (action == null) throw new ArgumentNullException("action");
127             if (scheduler == null) throw new ArgumentNullException("scheduler");
128
129             return factory
130                 .StartNewDelayed(millisecondsDelay, cancellationToken)
131                 .ContinueWith(_ => action(), cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
132         }
133
134         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
135         /// <param name="factory">The factory to use to create the task.</param>
136         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
137         /// <param name="action">The delegate executed by the task.</param>
138         /// <param name="state">An object provided to the delegate.</param>
139         /// <returns>The created Task.</returns>
140         public static Task StartNewDelayed(
141             this TaskFactory factory,
142             int millisecondsDelay, Action<object> action, object state)
143         {
144             if (factory == null) throw new ArgumentNullException("factory");
145             return StartNewDelayed(factory, millisecondsDelay, action, state, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
146         }
147
148         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
149         /// <param name="factory">The factory to use to create the task.</param>
150         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
151         /// <param name="action">The delegate executed by the task.</param>
152         /// <param name="state">An object provided to the delegate.</param>
153         /// <param name="creationOptions">Options that control the task's behavior.</param>
154         /// <returns>The created Task.</returns>
155         public static Task StartNewDelayed(
156             this TaskFactory factory,
157             int millisecondsDelay, Action<object> action, object state,
158             TaskCreationOptions creationOptions)
159         {
160             if (factory == null) throw new ArgumentNullException("factory");
161             return StartNewDelayed(factory, millisecondsDelay, action, state, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
162         }
163
164         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
165         /// <param name="factory">The factory to use to create the task.</param>
166         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
167         /// <param name="action">The delegate executed by the task.</param>
168         /// <param name="state">An object provided to the delegate.</param>
169         /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
170         /// <returns>The created Task.</returns>
171         public static Task StartNewDelayed(
172             this TaskFactory factory,
173             int millisecondsDelay, Action<object> action, object state,
174             CancellationToken cancellationToken)
175         {
176             if (factory == null) throw new ArgumentNullException("factory");
177             return StartNewDelayed(factory, millisecondsDelay, action, state, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
178         }
179
180         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
181         /// <param name="factory">The factory to use to create the task.</param>
182         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
183         /// <param name="action">The delegate executed by the task.</param>
184         /// <param name="state">An object provided to the delegate.</param>
185         /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
186         /// <param name="creationOptions">Options that control the task's behavior.</param>
187         /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
188         /// <returns>The created Task.</returns>
189         public static Task StartNewDelayed(
190             this TaskFactory factory,
191             int millisecondsDelay, Action<object> action, object state,
192             CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
193         {
194             if (factory == null) throw new ArgumentNullException("factory");
195             if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
196             if (action == null) throw new ArgumentNullException("action");
197             if (scheduler == null) throw new ArgumentNullException("scheduler");
198
199             // Create the task that will be returned; workaround for no ContinueWith(..., state) overload.
200             var result = new TaskCompletionSource<object>(state);
201
202             // Delay a continuation to run the action
203             factory
204                 .StartNewDelayed(millisecondsDelay, cancellationToken)
205                 .ContinueWith(t =>
206                 {
207                     if (t.IsCanceled) result.TrySetCanceled();
208                     else
209                     {
210                         try
211                         {
212                             action(state);
213                             result.TrySetResult(null);
214                         }
215                         catch (Exception exc) { result.TrySetException(exc); }
216                     }
217                 }, scheduler);
218
219             // Return the task
220             return result.Task;
221         }
222         #endregion
223
224         #region TaskFactory<TResult> with Func
225         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
226         /// <param name="factory">The factory to use to create the task.</param>
227         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
228         /// <param name="function">The delegate executed by the task.</param>
229         /// <returns>The created Task.</returns>
230         public static Task<TResult> StartNewDelayed<TResult>(
231             this TaskFactory<TResult> factory,
232             int millisecondsDelay, Func<TResult> function)
233         {
234             if (factory == null) throw new ArgumentNullException("factory");
235             return StartNewDelayed(factory, millisecondsDelay, function, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
236         }
237
238         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
239         /// <param name="factory">The factory to use to create the task.</param>
240         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
241         /// <param name="function">The delegate executed by the task.</param>
242         /// <param name="creationOptions">Options that control the task's behavior.</param>
243         /// <returns>The created Task.</returns>
244         public static Task<TResult> StartNewDelayed<TResult>(
245             this TaskFactory<TResult> factory,
246             int millisecondsDelay, Func<TResult> function,
247             TaskCreationOptions creationOptions)
248         {
249             if (factory == null) throw new ArgumentNullException("factory");
250             return StartNewDelayed(factory, millisecondsDelay, function, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
251         }
252
253         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
254         /// <param name="factory">The factory to use to create the task.</param>
255         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
256         /// <param name="function">The delegate executed by the task.</param>
257         /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
258         /// <returns>The created Task.</returns>
259         public static Task<TResult> StartNewDelayed<TResult>(
260             this TaskFactory<TResult> factory,
261             int millisecondsDelay, Func<TResult> function,
262             CancellationToken cancellationToken)
263         {
264             if (factory == null) throw new ArgumentNullException("factory");
265             return StartNewDelayed(factory, millisecondsDelay, function, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
266         }
267
268         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
269         /// <param name="factory">The factory to use to create the task.</param>
270         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
271         /// <param name="function">The delegate executed by the task.</param>
272         /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
273         /// <param name="creationOptions">Options that control the task's behavior.</param>
274         /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
275         /// <returns>The created Task.</returns>
276         public static Task<TResult> StartNewDelayed<TResult>(
277             this TaskFactory<TResult> factory,
278             int millisecondsDelay, Func<TResult> function,
279             CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
280         {
281             if (factory == null) throw new ArgumentNullException("factory");
282             if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
283             if (function == null) throw new ArgumentNullException("function");
284             if (scheduler == null) throw new ArgumentNullException("scheduler");
285
286             // Create the trigger and the timer to start it
287             var tcs = new TaskCompletionSource<object>();
288             var timer = new Timer(obj => ((TaskCompletionSource<object>)obj).SetResult(null),
289                 tcs, millisecondsDelay, Timeout.Infinite);
290
291             // Return a task that executes the function when the trigger fires
292             return tcs.Task.ContinueWith(_ =>
293             {
294                 timer.Dispose();
295                 return function();
296             }, cancellationToken, ContinuationOptionsFromCreationOptions(creationOptions), scheduler);
297         }
298
299         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
300         /// <param name="factory">The factory to use to create the task.</param>
301         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
302         /// <param name="function">The delegate executed by the task.</param>
303         /// <param name="state">An object provided to the delegate.</param>
304         /// <returns>The created Task.</returns>
305         public static Task<TResult> StartNewDelayed<TResult>(
306             this TaskFactory<TResult> factory,
307             int millisecondsDelay, Func<object, TResult> function, object state)
308         {
309             if (factory == null) throw new ArgumentNullException("factory");
310             return StartNewDelayed(factory, millisecondsDelay, function, state, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
311         }
312
313         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
314         /// <param name="factory">The factory to use to create the task.</param>
315         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
316         /// <param name="function">The delegate executed by the task.</param>
317         /// <param name="state">An object provided to the delegate.</param>
318         /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
319         /// <returns>The created Task.</returns>
320         public static Task<TResult> StartNewDelayed<TResult>(
321             this TaskFactory<TResult> factory,
322             int millisecondsDelay, Func<object, TResult> function, object state,
323             CancellationToken cancellationToken)
324         {
325             if (factory == null) throw new ArgumentNullException("factory");
326             return StartNewDelayed(factory, millisecondsDelay, function, state, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
327         }
328
329         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
330         /// <param name="factory">The factory to use to create the task.</param>
331         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
332         /// <param name="function">The delegate executed by the task.</param>
333         /// <param name="state">An object provided to the delegate.</param>
334         /// <param name="creationOptions">Options that control the task's behavior.</param>
335         /// <returns>The created Task.</returns>
336         public static Task<TResult> StartNewDelayed<TResult>(
337             this TaskFactory<TResult> factory,
338             int millisecondsDelay, Func<object, TResult> function, object state,
339             TaskCreationOptions creationOptions)
340         {
341             if (factory == null) throw new ArgumentNullException("factory");
342             return StartNewDelayed(factory, millisecondsDelay, function, state, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
343         }
344
345         /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
346         /// <param name="factory">The factory to use to create the task.</param>
347         /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
348         /// <param name="function">The delegate executed by the task.</param>
349         /// <param name="state">An object provided to the delegate.</param>
350         /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
351         /// <param name="creationOptions">Options that control the task's behavior.</param>
352         /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
353         /// <returns>The created Task.</returns>
354         public static Task<TResult> StartNewDelayed<TResult>(
355             this TaskFactory<TResult> factory,
356             int millisecondsDelay, Func<object, TResult> function, object state,
357             CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
358         {
359             if (factory == null) throw new ArgumentNullException("factory");
360             if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
361             if (function == null) throw new ArgumentNullException("action");
362             if (scheduler == null) throw new ArgumentNullException("scheduler");
363
364             // Create the task that will be returned
365             var result = new TaskCompletionSource<TResult>(state);
366             Timer timer = null;
367
368             // Create the task that will run the user's function
369             var functionTask = new Task<TResult>(function, state, creationOptions);
370
371             // When the function task completes, transfer the results to the returned task
372             functionTask.ContinueWith(t =>
373             {
374                 result.SetFromTask(t);
375                 timer.Dispose();
376             }, cancellationToken, ContinuationOptionsFromCreationOptions(creationOptions) | TaskContinuationOptions.ExecuteSynchronously, scheduler);
377
378             // Start the timer for the trigger
379             timer = new Timer(obj => ((Task)obj).Start(scheduler),
380                 functionTask, millisecondsDelay, Timeout.Infinite);
381
382             return result.Task;
383         }
384         #endregion
385     }
386 }