Parallel.cs
Go to the documentation of this file.
1 // Parallel.cs
2 //
3 // Copyright (c) 2008 Jérémie "Garuma" Laval
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 //
24 
25 #if NET_4_0 || UNITY_5_3_OR_NEWER
26 using System;
29 using System.Threading;
30 using System.Runtime.InteropServices;
31 
32 namespace System.Threading.Tasks
33 {
34  public static class Parallel
35  {
36  internal static int GetBestWorkerNumber ()
37  {
38  return GetBestWorkerNumber (TaskScheduler.Current);
39  }
40 
41  internal static int GetBestWorkerNumber (TaskScheduler scheduler)
42  {
43  return Math.Min (Environment.ProcessorCount, (scheduler ?? TaskScheduler.Current).MaximumConcurrencyLevel);
44  }
45 
46  static int GetBestWorkerNumber (int from, int to, ParallelOptions options, out int step)
47  {
48  int num = GetBestWorkerNumber(options.TaskScheduler);
49  if (options != null && options.MaxDegreeOfParallelism != -1)
50  num = Math.Min (options.MaxDegreeOfParallelism, num);
51  // Integer range that each task process
52  if ((step = (to - from) / num) < 5) {
53  step = 5;
54  num = (to - from) / 5;
55  if (num < 1)
56  num = 1;
57  }
58 
59  return num;
60  }
61 
62  static void HandleExceptions (IEnumerable<Task> tasks)
63  {
64  HandleExceptions (tasks, null);
65  }
66 
67  static void HandleExceptions (IEnumerable<Task> tasks, ParallelLoopState.ExternalInfos infos)
68  {
69  List<Exception> exs = new List<Exception> ();
70  foreach (Task t in tasks) {
71  if (t.Exception != null)
72  exs.Add (t.Exception);
73  }
74 
75  if (exs.Count > 0) {
76  if (infos != null)
77  infos.IsExceptional = true;
78 
79  throw new AggregateException (exs).Flatten ();
80  }
81  }
82 
83  static void InitTasks (Task[] tasks, int count, Action action, ParallelOptions options)
84  {
85  TaskCreationOptions creation = TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
86 
87  for (int i = 0; i < count; i++) {
88  if (options == null)
89  tasks [i] = Task.Factory.StartNew (action, creation);
90  else
91  tasks [i] = Task.Factory.StartNew (action, options.CancellationToken, creation, options.TaskScheduler);
92  }
93  }
94 
95 #region For
96 
97  public static ParallelLoopResult For (int fromInclusive, int toExclusive, Action<int> body)
98  {
99  return For (fromInclusive, toExclusive, ParallelOptions.Default, body);
100  }
101 
102  public static ParallelLoopResult For (int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body)
103  {
104  return For (fromInclusive, toExclusive, ParallelOptions.Default, body);
105  }
106 
107  public static ParallelLoopResult For (int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int> body)
108  {
109  return For (fromInclusive, toExclusive, parallelOptions, (index, state) => body (index));
110  }
111 
112  public static ParallelLoopResult For (int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int, ParallelLoopState> body)
113  {
114  return For<object> (fromInclusive, toExclusive, parallelOptions, () => null, (i, s, l) => { body (i, s); return null; }, _ => {});
115  }
116 
117  public static ParallelLoopResult For<TLocal> (int fromInclusive,
118  int toExclusive,
119  Func<TLocal> localInit,
120  Func<int, ParallelLoopState, TLocal, TLocal> body,
121  Action<TLocal> localFinally)
122  {
123  return For<TLocal> (fromInclusive, toExclusive, ParallelOptions.Default, localInit, body, localFinally);
124  }
125 
126  public static ParallelLoopResult For<TLocal> (int fromInclusive,
127  int toExclusive,
128  ParallelOptions parallelOptions,
129  Func<TLocal> localInit,
130  Func<int, ParallelLoopState, TLocal, TLocal> body,
131  Action<TLocal> localFinally)
132  {
133  if (body == null)
134  throw new ArgumentNullException ("body");
135  if (localInit == null)
136  throw new ArgumentNullException ("localInit");
137  if (localFinally == null)
138  throw new ArgumentNullException ("localFinally");
139  if (parallelOptions == null)
140  throw new ArgumentNullException ("options");
141  if (fromInclusive >= toExclusive)
142  return new ParallelLoopResult (null, true);
143 
144  // Number of task toExclusive be launched (normally == Env.ProcessorCount)
145  int step;
146  int num = GetBestWorkerNumber (fromInclusive, toExclusive, parallelOptions, out step);
147 
148  Task[] tasks = new Task [num];
149 
150  StealRange[] ranges = new StealRange[num];
151  for (int i = 0; i < num; i++)
152  ranges[i] = new StealRange (fromInclusive, i, step);
153 
155 
156  int currentIndex = -1;
157 
158  Action workerMethod = delegate {
159  int localWorker = Interlocked.Increment (ref currentIndex);
160  StealRange range = ranges[localWorker];
161  int index = range.V64.Actual;
162  int stopIndex = localWorker + 1 == num ? toExclusive : Math.Min (toExclusive, index + step);
163  TLocal local = localInit ();
164 
165  ParallelLoopState state = new ParallelLoopState (infos);
166  CancellationToken token = parallelOptions.CancellationToken;
167 
168  try {
169  for (int i = index; i < stopIndex;) {
170  if (infos.IsStopped)
171  return;
172 
174 
175  if (i >= stopIndex - range.V64.Stolen)
176  break;
177 
178  if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i)
179  return;
180 
181  state.CurrentIteration = i;
182  local = body (i, state, local);
183 
184  if (i + 1 >= stopIndex - range.V64.Stolen)
185  break;
186 
187  range.V64.Actual = ++i;
188  }
189 
190  bool sixtyfour = IntPtr.Size == 8; // Environment.Is64BitProcess;
191 
192  // Try toExclusive steal fromInclusive our right neighbor (cyclic)
193  int len = num + localWorker;
194  for (int sIndex = localWorker + 1; sIndex < len; ++sIndex) {
195  int extWorker = sIndex % num;
196  range = ranges[extWorker];
197 
198  stopIndex = extWorker + 1 == num ? toExclusive : Math.Min (toExclusive, fromInclusive + (extWorker + 1) * step);
199  int stolen = -1;
200 
201  do {
202  do {
203  long old;
204  StealValue64 val = new StealValue64 ();
205 
206  old = sixtyfour ? range.V64.Value : Interlocked.CompareExchange (ref range.V64.Value, 0, 0);
207  val.Value = old;
208 
209  if (val.Actual >= stopIndex - val.Stolen - 2)
210  goto next;
211  stolen = (val.Stolen += 1);
212 
213  if (Interlocked.CompareExchange (ref range.V64.Value, val.Value, old) == old)
214  break;
215  } while (true);
216 
217  stolen = stopIndex - stolen;
218 
219  if (stolen > range.V64.Actual)
220  local = body (stolen, state, local);
221  else
222  break;
223  } while (true);
224 
225  next:
226  continue;
227  }
228  } finally {
229  localFinally (local);
230  }
231  };
232 
233  InitTasks (tasks, num, workerMethod, parallelOptions);
234 
235  try {
236  Task.WaitAll (tasks);
237  } catch {
238  HandleExceptions (tasks, infos);
239  }
240 
241  return new ParallelLoopResult (infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional));
242  }
243 
244  [StructLayout(LayoutKind.Explicit)]
245  struct StealValue64 {
246  [FieldOffset(0)]
247  public long Value;
248  [FieldOffset(0)]
249  public int Actual;
250  [FieldOffset(4)]
251  public int Stolen;
252  }
253 
254  class StealRange
255  {
256  public StealValue64 V64 = new StealValue64 ();
257 
258  public StealRange (int fromInclusive, int i, int step)
259  {
260  V64.Actual = fromInclusive + i * step;
261  }
262  }
263 
264 #endregion
265 
266 #region For (long)
267 
268  [MonoTODO]
269  public static ParallelLoopResult For (long fromInclusive, long toExclusive, Action<long> body)
270  {
271  return For (fromInclusive, toExclusive, ParallelOptions.Default, body);
272  }
273 
274  [MonoTODO]
275  public static ParallelLoopResult For (long fromInclusive, long toExclusive, Action<long, ParallelLoopState> body)
276  {
277  return For (fromInclusive, toExclusive, ParallelOptions.Default, body);
278  }
279 
280  [MonoTODO]
281  public static ParallelLoopResult For (long fromInclusive, long toExclusive, ParallelOptions parallelOptions, Action<long> body)
282  {
283  return For (fromInclusive, toExclusive, parallelOptions, (index, state) => body (index));
284  }
285 
286  [MonoTODO]
287  public static ParallelLoopResult For (long fromInclusive, long toExclusive, ParallelOptions parallelOptions, Action<long, ParallelLoopState> body)
288  {
289  return For<object> (fromInclusive, toExclusive, parallelOptions, () => null, (i, s, l) => { body (i, s); return null; }, _ => {});
290  }
291 
292  [MonoTODO]
293  public static ParallelLoopResult For<TLocal> (long fromInclusive,
294  long toExclusive,
295  Func<TLocal> localInit,
296  Func<long, ParallelLoopState, TLocal, TLocal> body,
297  Action<TLocal> localFinally)
298  {
299  return For<TLocal> (fromInclusive, toExclusive, ParallelOptions.Default, localInit, body, localFinally);
300  }
301 
302  [MonoTODO ("See how this can be refactored with the above For implementation")]
303  public static ParallelLoopResult For<TLocal> (long fromInclusive,
304  long toExclusive,
305  ParallelOptions parallelOptions,
306  Func<TLocal> localInit,
307  Func<long, ParallelLoopState, TLocal, TLocal> body,
308  Action<TLocal> localFinally)
309  {
310  if (body == null)
311  throw new ArgumentNullException ("body");
312  if (localInit == null)
313  throw new ArgumentNullException ("localInit");
314  if (localFinally == null)
315  throw new ArgumentNullException ("localFinally");
316  if (parallelOptions == null)
317  throw new ArgumentNullException ("options");
318  if (fromInclusive >= toExclusive)
319  return new ParallelLoopResult (null, true);
320 
321  throw new NotImplementedException ();
322  }
323 
324 #endregion
325 
326 #region Foreach
327  // Spicy Pixel: Made internal
328  internal static ParallelLoopResult ForEach<TSource, TLocal> (Func<int, IList<IEnumerator<TSource>>> enumerable, ParallelOptions options,
329  Func<TLocal> init, Func<TSource, ParallelLoopState, TLocal, TLocal> action,
330  Action<TLocal> destruct)
331  {
332  if (enumerable == null)
333  throw new ArgumentNullException ("source");
334  if (options == null)
335  throw new ArgumentNullException ("options");
336  if (action == null)
337  throw new ArgumentNullException ("action");
338  if (init == null)
339  throw new ArgumentNullException ("init");
340  if (destruct == null)
341  throw new ArgumentNullException ("destruct");
342 
343  int num = Math.Min (GetBestWorkerNumber (options.TaskScheduler),
344  options != null && options.MaxDegreeOfParallelism != -1 ? options.MaxDegreeOfParallelism : int.MaxValue);
345 
346  Task[] tasks = new Task[num];
348 
350  const int bagCount = 5;
351 
352  IList<IEnumerator<TSource>> slices = enumerable (num);
353 
354  int sliceIndex = -1;
355 
356  Action workerMethod = delegate {
357  IEnumerator<TSource> slice = slices[Interlocked.Increment (ref sliceIndex)];
358 
359  TLocal local = init ();
360  ParallelLoopState state = new ParallelLoopState (infos);
361  int workIndex = bag.GetNextIndex ();
362  CancellationToken token = options.CancellationToken;
363 
364  try {
365  bool cont = true;
366  TSource element;
367 
368  while (cont) {
369  if (infos.IsStopped || infos.IsBroken.Value)
370  return;
371 
373 
374  for (int i = 0; i < bagCount && (cont = slice.MoveNext ()); i++) {
375  bag.Add (workIndex, slice.Current);
376  }
377 
378  for (int i = 0; i < bagCount && bag.TryTake (workIndex, out element); i++) {
379  if (infos.IsStopped)
380  return;
381 
383 
384  local = action (element, state, local);
385  }
386  }
387 
388  while (bag.TrySteal (workIndex, out element)) {
390 
391  local = action (element, state, local);
392 
393  if (infos.IsStopped || infos.IsBroken.Value)
394  return;
395  }
396  } finally {
397  destruct (local);
398  }
399  };
400 
401  InitTasks (tasks, num, workerMethod, options);
402 
403  try {
404  Task.WaitAll (tasks);
405  } catch {
406  HandleExceptions (tasks, infos);
407  }
408 
409  return new ParallelLoopResult (infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional));
410  }
411 
412  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, Action<TSource> body)
413  {
414  if (source == null)
415  throw new ArgumentNullException ("source");
416  if (body == null)
417  throw new ArgumentNullException ("body");
418 
419  return ForEach<TSource, object> (Partitioner.Create (source),
420  ParallelOptions.Default,
421  () => null,
422  (e, s, l) => { body (e); return null; },
423  _ => {});
424  }
425 
426  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, Action<TSource, ParallelLoopState> body)
427  {
428  if (source == null)
429  throw new ArgumentNullException ("source");
430  if (body == null)
431  throw new ArgumentNullException ("body");
432 
433  return ForEach<TSource, object> (Partitioner.Create (source),
434  ParallelOptions.Default,
435  () => null,
436  (e, s, l) => { body (e, s); return null; },
437  _ => {});
438  }
439 
440  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source,
441  Action<TSource, ParallelLoopState, long> body)
442  {
443  if (source == null)
444  throw new ArgumentNullException ("source");
445  if (body == null)
446  throw new ArgumentNullException ("body");
447 
448 
449  return ForEach<TSource, object> (Partitioner.Create (source),
450  ParallelOptions.Default,
451  () => null,
452  (e, s, l) => { body (e, s, -1); return null; },
453  _ => {});
454  }
455 
457  Action<TSource, ParallelLoopState> body)
458  {
459  if (body == null)
460  throw new ArgumentNullException ("body");
461 
462  return ForEach<TSource, object> (source,
463  ParallelOptions.Default,
464  () => null,
465  (e, s, l) => { body (e, s); return null; },
466  _ => {});
467  }
468 
470  Action<TSource, ParallelLoopState, long> body)
471 
472  {
473  if (body == null)
474  throw new ArgumentNullException ("body");
475 
476  return ForEach<TSource, object> (source,
477  ParallelOptions.Default,
478  () => null,
479  (e, s, i, l) => { body (e, s, i); return null; },
480  _ => {});
481  }
482 
484  Action<TSource> body)
485 
486  {
487  if (body == null)
488  throw new ArgumentNullException ("body");
489 
490  return ForEach<TSource, object> (source,
491  ParallelOptions.Default,
492  () => null,
493  (e, s, l) => { body (e); return null; },
494  _ => {});
495  }
496 
497  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source,
498  ParallelOptions parallelOptions,
499  Action<TSource> body)
500  {
501  if (source == null)
502  throw new ArgumentNullException ("source");
503  if (body == null)
504  throw new ArgumentNullException ("body");
505 
506  return ForEach<TSource, object> (Partitioner.Create (source),
507  parallelOptions,
508  () => null,
509  (e, s, l) => { body (e); return null; },
510  _ => {});
511  }
512 
513  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
514  Action<TSource, ParallelLoopState> body)
515  {
516  if (source == null)
517  throw new ArgumentNullException ("source");
518  if (body == null)
519  throw new ArgumentNullException ("body");
520 
521  return ForEach<TSource, object> (Partitioner.Create (source),
522  parallelOptions,
523  () => null,
524  (e, s, l) => { body (e, s); return null; },
525  _ => {});
526  }
527 
528  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
529  Action<TSource, ParallelLoopState, long> body)
530  {
531  if (source == null)
532  throw new ArgumentNullException ("source");
533  if (body == null)
534  throw new ArgumentNullException ("body");
535 
536  return ForEach<TSource, object> (Partitioner.Create (source),
537  parallelOptions,
538  () => null,
539  (e, s, i, l) => { body (e, s, i); return null; },
540  _ => {});
541  }
542 
544  Action<TSource, ParallelLoopState, long> body)
545 
546  {
547  if (body == null)
548  throw new ArgumentNullException ("body");
549 
550  return ForEach<TSource, object> (source,
551  parallelOptions,
552  () => null,
553  (e, s, i, l) => { body (e, s, i); return null; },
554  _ => {});
555  }
556 
558  Action<TSource> body)
559  {
560  if (body == null)
561  throw new ArgumentNullException ("body");
562 
563  return ForEach<TSource, object> (source,
564  parallelOptions,
565  () => null,
566  (e, s, l) => { body (e); return null; },
567  _ => {});
568  }
569 
571  Action<TSource, ParallelLoopState> body)
572  {
573  return ForEach<TSource, object> (source,
574  parallelOptions,
575  () => null,
576  (e, s, l) => { body (e, s); return null; },
577  _ => {});
578  }
579 
580  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, Func<TLocal> localInit,
581  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
582  Action<TLocal> localFinally)
583  {
584  if (source == null)
585  throw new ArgumentNullException ("source");
586 
587  return ForEach<TSource, TLocal> ((Partitioner<TSource>)Partitioner.Create (source),
588  ParallelOptions.Default,
589  localInit,
590  body,
591  localFinally);
592  }
593 
594  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, Func<TLocal> localInit,
595  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
596  Action<TLocal> localFinally)
597  {
598  return ForEach<TSource, TLocal> (Partitioner.Create (source),
599  ParallelOptions.Default,
600  localInit,
601  body,
602  localFinally);
603  }
604 
605  public static ParallelLoopResult ForEach<TSource, TLocal> (OrderablePartitioner<TSource> source, Func<TLocal> localInit,
606  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
607  Action<TLocal> localFinally)
608  {
609  return ForEach<TSource, TLocal> (source, ParallelOptions.Default, localInit, body, localFinally);
610  }
611 
612  public static ParallelLoopResult ForEach<TSource, TLocal> (Partitioner<TSource> source, Func<TLocal> localInit,
613  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
614  Action<TLocal> localFinally)
615  {
616  return ForEach<TSource, TLocal> (source, ParallelOptions.Default, localInit, body, localFinally);
617  }
618 
619  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
620  Func<TLocal> localInit,
621  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
622  Action<TLocal> localFinally)
623  {
624  if (source == null)
625  throw new ArgumentNullException ("source");
626 
627  return ForEach<TSource, TLocal> (Partitioner.Create (source), parallelOptions, localInit, body, localFinally);
628  }
629 
630  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
631  Func<TLocal> localInit,
632  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
633  Action<TLocal> localFinally)
634  {
635  if (source == null)
636  throw new ArgumentNullException ("source");
637 
638  return ForEach<TSource, TLocal> (Partitioner.Create (source), parallelOptions, localInit, body, localFinally);
639  }
640 
641  public static ParallelLoopResult ForEach<TSource, TLocal> (Partitioner<TSource> source, ParallelOptions parallelOptions,
642  Func<TLocal> localInit,
643  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
644  Action<TLocal> localFinally)
645  {
646  if (source == null)
647  throw new ArgumentNullException ("source");
648  if (body == null)
649  throw new ArgumentNullException ("body");
650 
651  return ForEach<TSource, TLocal> (source.GetPartitions, parallelOptions, localInit, body, localFinally);
652  }
653 
654  public static ParallelLoopResult ForEach<TSource, TLocal> (OrderablePartitioner<TSource> source, ParallelOptions parallelOptions,
655  Func<TLocal> localInit,
656  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
657  Action<TLocal> localFinally)
658  {
659  if (source == null)
660  throw new ArgumentNullException ("source");
661  if (body == null)
662  throw new ArgumentNullException ("body");
663 
664  return ForEach<KeyValuePair<long, TSource>, TLocal> (source.GetOrderablePartitions,
665  parallelOptions,
666  localInit,
667  (e, s, l) => body (e.Value, s, e.Key, l),
668  localFinally);
669  }
670  #endregion
671 
672  #region Invoke
673  public static void Invoke (params Action[] actions)
674  {
675  if (actions == null)
676  throw new ArgumentNullException ("actions");
677 
678  Invoke (ParallelOptions.Default, actions);
679  }
680 
681  public static void Invoke (ParallelOptions parallelOptions, params Action[] actions)
682  {
683  if (parallelOptions == null)
684  throw new ArgumentNullException ("parallelOptions");
685  if (actions == null)
686  throw new ArgumentNullException ("actions");
687  if (actions.Length == 0)
688  throw new ArgumentException ("actions is empty");
689  foreach (var a in actions)
690  if (a == null)
691  throw new ArgumentException ("One action in actions is null", "actions");
692  if (actions.Length == 1) {
693  actions[0] ();
694  return;
695  }
696 
697  Task[] ts = new Task[actions.Length];
698  for (int i = 0; i < ts.Length; i++)
699  ts[i] = Task.Factory.StartNew (actions[i],
700  parallelOptions.CancellationToken,
701  TaskCreationOptions.None,
702  parallelOptions.TaskScheduler);
703 
704  try {
705  Task.WaitAll (ts, parallelOptions.CancellationToken);
706  } catch {
707  HandleExceptions (ts);
708  }
709  }
710  #endregion
711 
712  #region SpawnBestNumber, used by PLinq
713  internal static Task[] SpawnBestNumber (Action action, Action callback)
714  {
715  return SpawnBestNumber (action, -1, callback);
716  }
717 
718  internal static Task[] SpawnBestNumber (Action action, int dop, Action callback)
719  {
720  return SpawnBestNumber (action, dop, false, callback);
721  }
722 
723  internal static Task[] SpawnBestNumber (Action action, int dop, bool wait, Action callback)
724  {
725  // Get the optimum amount of worker to create
726  int num = dop == -1 ? (wait ? GetBestWorkerNumber () + 1 : GetBestWorkerNumber ()) : dop;
727 
728  // Initialize worker
729  CountdownEvent evt = new CountdownEvent (num);
730  Task[] tasks = new Task [num];
731  for (int i = 0; i < num; i++) {
732  tasks [i] = Task.Factory.StartNew (() => {
733  action ();
734  evt.Signal ();
735  if (callback != null && evt.IsSet)
736  callback ();
737  });
738  }
739 
740  // If explicitely told, wait for all workers to complete
741  // and thus let main thread participate in the processing
742  if (wait)
743  Task.WaitAll (tasks);
744 
745  return tasks;
746  }
747 #endregion
748  }
749 }
750 #endif
static ParallelLoopResult For(long fromInclusive, long toExclusive, ParallelOptions parallelOptions, Action< long > body)
Definition: Parallel.cs:281
abstract IList< IEnumerator< KeyValuePair< long, TSource > > > GetOrderablePartitions(int partitionCount)
static ParallelLoopResult For(long fromInclusive, long toExclusive, ParallelOptions parallelOptions, Action< long, ParallelLoopState > body)
Definition: Parallel.cs:287
static ParallelLoopResult For< TLocal >(int fromInclusive, int toExclusive, Func< TLocal > localInit, Func< int, ParallelLoopState, TLocal, TLocal > body, Action< TLocal > localFinally)
Definition: Parallel.cs:117
static void Invoke(ParallelOptions parallelOptions, params Action[] actions)
Definition: Parallel.cs:681
static ParallelLoopResult For(int fromInclusive, int toExclusive, Action< int, ParallelLoopState > body)
Definition: Parallel.cs:102
static ParallelLoopResult For(long fromInclusive, long toExclusive, Action< long, ParallelLoopState > body)
Definition: Parallel.cs:275
static ParallelLoopResult For(int fromInclusive, int toExclusive, Action< int > body)
Definition: Parallel.cs:97
static ParallelLoopResult For(long fromInclusive, long toExclusive, Action< long > body)
Definition: Parallel.cs:269
static ParallelLoopResult ForEach< TSource >(IEnumerable< TSource > source, Action< TSource > body)
Definition: Parallel.cs:412
static void Invoke(params Action[] actions)
Definition: Parallel.cs:673
static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action< int > body)
Definition: Parallel.cs:107
AggregateException Flatten()
static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action< int, ParallelLoopState > body)
Definition: Parallel.cs:112