Beispiel #1
0
        private static void Sort <T>(T[] collection, int maxDegreeOfParallelism, IComparer <T> comparer, [NotNull] SortState state)
        {
            const int sequentialThreshold = 2048;

            // Other threads already processed all work before this one started. ActiveWorkerCount is already 0
            if (state.Partitions.IsEmpty)
            {
                state.Release();
                return;
            }

            // This thread is now actively processing work items, meaning there might be work in progress
            Interlocked.Increment(ref state.ActiveWorkerCount);

            var hasChild = false;

            try
            {
                SortRange range;
                while (state.Partitions.TryDequeue(out range))
                {
                    if (range.Right - range.Left < sequentialThreshold)
                    {
                        // Sort small collections sequentially
                        Array.Sort(collection, range.Left, range.Right - range.Left + 1, comparer);
                    }
                    else
                    {
                        var pivot = Partition(collection, range.Left, range.Right, comparer);

                        // Add work items
                        if (pivot - 1 > range.Left)
                        {
                            state.Partitions.Enqueue(new SortRange(range.Left, pivot - 1));
                        }

                        if (range.Right > pivot + 1)
                        {
                            state.Partitions.Enqueue(new SortRange(pivot + 1, range.Right));
                        }

                        // Add a new worker if necessary
                        if (maxDegreeOfParallelism > 1 && !hasChild)
                        {
                            state.AddReference();
                            Fork(collection, maxDegreeOfParallelism, comparer, state);
                            hasChild = true;
                        }
                    }
                }
            }
            finally
            {
                state.Release();

                if (Interlocked.Decrement(ref state.ActiveWorkerCount) == 0)
                {
                    state.Finished.Set();
                }
            }
        }
Beispiel #2
0
        private static void SortOnThread <T>(T[] collection, IComparer <T> comparer, [NotNull] SortState state)
        {
            const int sequentialThreshold = 2048;

            var hasChild = false;

            try
            {
                var sw = new SpinWait();
                while (Volatile.Read(ref state.OpLeft) != 0)
                {
                    if (state.Partitions.TryDequeue(out var range) == false)
                    {
                        sw.SpinOnce();
                        continue;
                    }

                    if (range.Right - range.Left < sequentialThreshold)
                    {
                        // Sort small collections sequentially
                        Array.Sort(collection, range.Left, range.Right - range.Left + 1, comparer);
                        Interlocked.Decrement(ref state.OpLeft);
                    }
                    else
                    {
                        var pivot = Partition(collection, range.Left, range.Right, comparer);

                        int delta = -1;
                        // Add work items
                        if (pivot - 1 > range.Left)
                        {
                            delta++;
                        }

                        if (range.Right > pivot + 1)
                        {
                            delta++;
                        }

                        Interlocked.Add(ref state.OpLeft, delta);

                        if (pivot - 1 > range.Left)
                        {
                            state.Partitions.Enqueue(new SortRange(range.Left, pivot - 1));
                        }


                        if (range.Right > pivot + 1)
                        {
                            state.Partitions.Enqueue(new SortRange(pivot + 1, range.Right));
                        }


                        // Add a new worker if necessary
                        if (!hasChild)
                        {
                            var w = Interlocked.Decrement(ref state.MaxWorkerCount);
                            if (w >= 0)
                            {
                                state.AddReference();
                                ThreadPool.Instance.QueueWorkItem(() => SortOnThread(collection, comparer, state));
                            }
                            hasChild = true;
                        }
                    }
                }
            }
            finally
            {
                if (Volatile.Read(ref state.OpLeft) == 0)
                {
                    state.Finished.Set();
                }
                state.Release();
            }
        }