1// Bounded thread pool with a blocking parallel_for. Threads are created once (lazy singleton) and reused.2#pragma once3#include <functional>4#include <thread>5#include <vector>6#include <atomic>7#include <mutex>8#include <condition_variable>9#include <deque>10#include <exception>11#include "raid/core/types.hpp"1213namespace raid {1415class ThreadPool {16 public:17 explicit ThreadPool(unsigned n_threads = 0);18 ~ThreadPool();19 ThreadPool(const ThreadPool&) = delete;20 ThreadPool& operator=(const ThreadPool&) = delete;21 unsigned size() const { return static_cast<unsigned>(workers_.size()); }22 /// Runs fn(begin, end) over [0,n) split in chunks of `grain` (0 = automatic). Blocks until all chunks finished.23 /// Exceptions thrown by fn are rethrown on the calling thread (first one).24 void parallel_for(usize n, const std::function<void(usize, usize)>& fn, usize grain = 0);25 /// Global pool sized to hardware concurrency (or RAID_THREADS env var).26 static ThreadPool& global();2728 private:29 void worker();30 std::vector<std::thread> workers_;31 std::deque<std::function<void()>> queue_;32 std::mutex m_;33 std::condition_variable cv_;34 bool stop_{false};35};3637/// Serial fallback helper: parallel_for with n_threads==1 semantics.38inline void serial_for(usize n, const std::function<void(usize, usize)>& fn) { if (n) fn(0, n); }3940} // namespace raid41