- Enqueue(vector) dropped tasks when the count didn't divide by the
workers: the last one got only the remainder. Tasks are now split as
evenly as the count allows, each worker's taskCount grows by what it
was given (the single-task Enqueue picks by it), and Start(1), which
has no workers, leaves the batch for the caller's JoinPool.
- Stop wakes every slot, JoinPool's too, after joining the workers: a
thread that had joined the pool slept on. It takes each slot's mutex
before notifying, so a waiter between its check and its sleep can't miss
the wake-up, and works on the pool it started with. Again, or before
Start, it does nothing; joining a thread twice threw. Its documentation
says what it doesn't do: stop from a pool task, or from two threads at
once, run tasks enqueued once it has begun, or have JoinPool wait for it.
- Tests: EnqueueBatch, StopJoinPool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>