public void Execute(WorkerStep step) { lock (this) { Interlocked.Exchange(ref _batchIndex, -1); // -1 because Interlocked.Increment returns the *incremented* value _step = step; if (_outstandingWorkersNeedsSync != 0) { throw new InvalidOperationException("There are still outstanding workers!"); } _outstandingWorkersNeedsSync = _workerCount; } for (int i = 1; i < _workerCount; i++) // the current thread will be worker 0 { ThreadPool.QueueUserWorkItem(_executeImpl, this); } ExecuteImpl(); // lend a hand ourselves lock (this) { if (_outstandingWorkersNeedsSync != 0 && !Monitor.Wait(this, millisecondsTimeout: 10_000)) { throw new TimeoutException("Timeout waiting for parallel workers to complete"); } } }
private void Execute(WorkerStep step, int batchIndex, int start, int end) { int count = end - start; // Console.WriteLine($"{step}/{_shift}/{batchIndex}: [{start},{end}] ({count}) on thread {Environment.CurrentManagedThreadId}"); switch (step) { case WorkerStep.Copy: _keys.Span.Slice(start, count).CopyTo(_workspace.Span.Slice(start, count)); break; case WorkerStep.BucketCountAscending: case WorkerStep.BucketCountDescending: { var keys = _keys.Span.NonPortableCast <T, uint>(); var buckets = _countsOffsets.Span.NonPortableCast <T, uint>().Slice( batchIndex * _bucketCount, _bucketCount); if (step == WorkerStep.BucketCountAscending) { BucketCountAscending(buckets, keys, start, end, _shift, _groupMask); } else { BucketCountDescending(buckets, keys, start, end, _shift, _groupMask); } } break; case WorkerStep.ApplyAscending: case WorkerStep.ApplyDescending: { var offsets = _countsOffsets.Span.NonPortableCast <T, uint>().Slice( batchIndex * _bucketCount, _bucketCount); if (NeedsApply(offsets)) { var keys = _keys.Span.NonPortableCast <T, uint>(); var workspace = _workspace.Span.NonPortableCast <T, uint>(); if (step == WorkerStep.ApplyAscending) { ApplyAscending(offsets, keys, workspace, start, end, _shift, _groupMask); } else { ApplyDescending(offsets, keys, workspace, start, end, _shift, _groupMask); } } else { _keys.Span.Slice(start, count).CopyTo(_workspace.Span.Slice((int)offsets[0], count)); } } break; default: throw new NotImplementedException($"Unknown worker step: {step}"); } }