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(); } } }
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(); } }