TaskFactory_T.cs 20 KB

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