Пример #1
0
        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)));
        }
Пример #2
0
        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)));
        }