public static ParallelLoopResult For <TLocal> (int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Func <TLocal> localInit, Func <int, ParallelLoopState, TLocal, TLocal> body, Action <TLocal> localFinally) { if (body == null) { throw new ArgumentNullException("body"); } if (localInit == null) { throw new ArgumentNullException("localInit"); } if (localFinally == null) { throw new ArgumentNullException("localFinally"); } if (parallelOptions == null) { throw new ArgumentNullException("options"); } if (fromInclusive >= toExclusive) { return(new ParallelLoopResult(null, true)); } // Number of task toExclusive be launched (normally == Env.ProcessorCount) int step; int num = GetBestWorkerNumber(fromInclusive, toExclusive, parallelOptions, out step); Task[] tasks = new Task [num]; StealRange[] ranges = new StealRange[num]; for (int i = 0; i < num; i++) { ranges[i] = new StealRange(fromInclusive, i, step); } ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos(); int currentIndex = -1; Action workerMethod = delegate { int localWorker = Interlocked.Increment(ref currentIndex); StealRange range = ranges[localWorker]; int index = range.V64.Actual; int stopIndex = localWorker + 1 == num ? toExclusive : Math.Min(toExclusive, index + step); TLocal local = localInit(); ParallelLoopState state = new ParallelLoopState(infos); CancellationToken token = parallelOptions.CancellationToken; try { for (int i = index; i < stopIndex;) { if (infos.IsStopped) { return; } token.ThrowIfCancellationRequested(); if (i >= stopIndex - range.V64.Stolen) { break; } if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i) { return; } state.CurrentIteration = i; local = body(i, state, local); if (i + 1 >= stopIndex - range.V64.Stolen) { break; } range.V64.Actual = ++i; } bool sixtyfour = IntPtr.Size == 8; // Environment.Is64BitProcess; // Try toExclusive steal fromInclusive our right neighbor (cyclic) int len = num + localWorker; for (int sIndex = localWorker + 1; sIndex < len; ++sIndex) { int extWorker = sIndex % num; range = ranges[extWorker]; stopIndex = extWorker + 1 == num ? toExclusive : Math.Min(toExclusive, fromInclusive + (extWorker + 1) * step); int stolen = -1; do { do { long old; StealValue64 val = new StealValue64(); old = sixtyfour ? range.V64.Value : Interlocked.CompareExchange(ref range.V64.Value, 0, 0); val.Value = old; if (val.Actual >= stopIndex - val.Stolen - 2) { goto next; } stolen = (val.Stolen += 1); if (Interlocked.CompareExchange(ref range.V64.Value, val.Value, old) == old) { break; } } while (true); stolen = stopIndex - stolen; if (stolen > range.V64.Actual) { local = body(stolen, state, local); } else { break; } } while (true); next: continue; } } finally { localFinally(local); } }; InitTasks(tasks, num, workerMethod, parallelOptions); try { Task.WaitAll(tasks); } catch { HandleExceptions(tasks, infos); } return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional))); }
public static ParallelLoopResult For <TLocal> (int from, int to, ParallelOptions options, Func <TLocal> init, Func <int, ParallelLoopState, TLocal, TLocal> action, Action <TLocal> destruct) { if (action == null) { throw new ArgumentNullException("action"); } if (init == null) { throw new ArgumentNullException("localInit"); } if (destruct == null) { throw new ArgumentNullException("localFinally"); } if (options == null) { throw new ArgumentNullException("options"); } if (from >= to) { return(new ParallelLoopResult(null, true)); } // Number of task to be launched (normally == Env.ProcessorCount) int step; int num = GetBestWorkerNumber(from, to, options, out step); Task[] tasks = new Task [num]; StealRange[] ranges = new StealRange[num]; for (int i = 0; i < num; i++) { ranges[i] = new StealRange(from, i, step); } ParallelLoopState.ExternalInfos infos = new ParallelLoopState.ExternalInfos(); int currentIndex = -1; Action workerMethod = delegate { int localWorker = Interlocked.Increment(ref currentIndex); StealRange range = ranges[localWorker]; int index = range.Actual; int stopIndex = localWorker + 1 == num ? to : Math.Min(to, index + step); TLocal local = init(); ParallelLoopState state = new ParallelLoopState(infos); CancellationToken token = options.CancellationToken; try { for (int i = index; i < stopIndex; range.Actual = ++i) { if (infos.IsStopped) { return; } token.ThrowIfCancellationRequested(); if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i) { return; } state.CurrentIteration = i; local = action(i, state, local); if (i >= stopIndex - range.Stolen) { break; } } // Try to steal from our right neighbor (cyclic) int len = num + localWorker; for (int sIndex = localWorker + 1; sIndex < len; ++sIndex) { int extWorker = sIndex % num; range = ranges[extWorker]; stopIndex = extWorker + 1 == num ? to : Math.Min(to, from + (extWorker + 1) * step); int stolen; do { stolen = range.Stolen; if (stopIndex - stolen > range.Actual) { goto next; } } while (Interlocked.CompareExchange(ref range.Stolen, stolen + 1, stolen) != stolen); stolen = stopIndex - stolen - 1; if (stolen > range.Actual) { local = action(stolen, state, local); } next: continue; } } finally { destruct(local); } }; InitTasks(tasks, num, workerMethod, options); try { Task.WaitAll(tasks); } catch { HandleExceptions(tasks, infos); } return(new ParallelLoopResult(infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional))); }