Cpp still does not have a standard 'parallel work dispatching' solution, AKA a thread pool. I dislike that name however, since unless the API provides access to the underlying threads, a thread pool is but one possible implementation (detail) of a 'parallel work dispatching' library.
Any name involving 'parallel' is a tongue breaker and 'worker' sounds too 'red' hence sweater - legal, portable, machine sweat shops that sweat for you.
(not an actual/official Boost library, simply started as another wannabe proposal)
Functionoid ConfigEx moodycamel::ConcurrentQueue
CI (.github/workflows) builds and runs the full test suite on every push/PR across
10 configurations: MSVC (Debug/Release), Clang-CL (Debug/Release), Clang (Debug/Release),
GCC (Debug/Release), Apple-Clang (Debug/Release) — i.e. Windows, Linux, and macOS, each
in both a debug (assertions on) and optimized configuration.
Current test targets (test/, GoogleTest):
sweater_smoke_test—sweat_shopbasics (spread_the_sweat/dispatch/fire_and_forget).sweater_rw_mutex_contract_test—TYPED_TEST_SUITE-based consolidation of the rw-mutex family's shared behavioral contracts, run once per concrete type instead of hand-duplicated per file (rw_mutex_contract_test.cpp):MutexContract(rw_mutex,futex_rw_mutex,reader_preferring_rw_mutex,reader_preferring_futex_rw_mutex) — preference-independent mutual-exclusion invariants (uncontended try-acquire, shared readers exclude a writer, a writer excludes everything, a writer blocks until an existing reader releases).WriterPreferringContract(rw_mutex,futex_rw_mutex) — a new reader is blocked once a writer is queued.ReaderPreferringContract(reader_preferring_rw_mutex,reader_preferring_futex_rw_mutex) — same-thread nested reads never deadlock behind a queued writer (unconditional on every platform); new-reader-admission despite a queued writer is trait-gated (mutex_test_traits.hpp'smutex_traits<Mutex>::admits_reader_with_writer_queued) since it only holds forreader_preferring_rw_mutexunder glibc's NP rwlock-kind extensions — elsewhere that name isrrw_mutex.hpp's per-thread hold-collapsing wrapper, which is "still writer-preferring underneath", and the testGTEST_SKIPs there instead of failing.GuardContract(rw_mutex,reader_preferring_rw_mutex) — RAII guards (rw_lock/basic_ro_lock<Mutex>) andstd::shared_lock/std::unique_lockinterop; scoped to just these two since they're the only types the guards bind to (the futex family is a separate, non-rw_mutex-derived hierarchy).FutexOnlyContract(futex_rw_mutex,reader_preferring_futex_rw_mutex) — copyability and a mutual-exclusion/progress stress test, kept scoped to just the futex pair rather than folded intoMutexContract: neitherrw_mutexnorreader_preferring_rw_mutexhad stress coverage before, and a genuinely reader-preferring lock under this stress shape's sustained read load can legitimately starve a writer, which would hang the test rather than fail it cleanly — a deliberate scope decision, not a consolidation byproduct.
sweater_rw_preference_test— type-identity checks for thewriter_preferring_rw_mutex/reader_preferring_rw_mutexsplit specific to glibc's NP rwlock-kind extensions (self-skips — compiles to zero tests — elsewhere; the behavioral coverage forreader_preferring_rw_mutexon those platforms now lives insweater_rw_mutex_contract_testabove).sweater_futex_test— low-levelpsi::thrd_lite::futexwait/wake, including the bitset-targetedwake_all/wait_if_equaloverloads (real filtering on LinuxFUTEX_WAIT_BITSET/FUTEX_WAKE_BITSET; a documented no-op elsewhere).sweater_futex_rw_mutex_test—futex_rw_mutex/reader_preferring_futex_rw_mutex(bleeding-edge,__ulock-based on Apple — see that header's own design-doc comment on why this isn't a production path there).sweater_shop_stress_test—sweat_shopdispatch/thread-pool adversarial coverage: a burst-enqueue test (fire-and-forget a batch of work, then confirm it all completes viawait_until_idle()before the shop goes out of scope — see the note below on why the shop's destructor alone cannot be relied on for this), a concurrent-producer stress test (many threads hammeringfire_and_forget/dispatch/spread_the_sweaton one shared shop), and a test documenting thatin_flight_count()/wait_until_idle()are tracked by a single process-wide counter, not one per shop (a shop with no work of its own can still observe, and wait on, a completely unrelated shop's in-flight work). Writing the concurrent-producer test surfaced a real bug (now fixed): the generic (Linux) impl'sspread_the_sweatincremented that process-wide counter once per dispatched work part but never decremented it (spread's own completion barrier already makes it synchronous, so it was never meant to be tracked there at all) — a permanent leak that would eventually makewait_until_idle()return false forever. Seework_added_untracked()inimpls/generic.hpp/generic.cpp.sweater_libuv_test— optional, only built when libuv headers/library are found.
shop::~shop() does not drain fire_and_forget work on every backend. The
generic (Linux) implementation owns a joinable worker-thread pool whose loop
drains its queue to empty before honoring shutdown, so destroying a shop there
happens to wait for already-enqueued work as a side effect. windows.hpp's and
apple.hpp's shops are explicitly stateless and submit fire_and_forget work
to the OS's shared, process-wide thread pool (Windows Thread Pool API / GCD's
global dispatch queue) — there is no per-shop thread to join, so destroying the
shop does not wait for anything there. Always call wait_until_idle() (or track
completion yourself) before relying on fire_and_forget work having finished;
do not rely on a shop's destructor or end-of-scope for this.
All of the above are green on every CI platform as of this writing. The rw-mutex family
in particular has been additionally stress-tested well beyond CI's single pass: repeated
--gtest_repeat runs (dozens of iterations) and separate process-spawn runs (tens of
runs) on both WSL/Linux and real Apple hardware, specifically to catch intermittent
concurrency bugs that a single green run can miss — two such bugs were in fact found and
fixed this way (see the futex_rw_mutex commit history).