#pragma once #include #include #include #include #include #include #include #include #include class ThreadPool { public: static ThreadPool &instance() { static ThreadPool pool(std::clamp(std::thread::hardware_concurrency(), 2u, 4u)); return pool; } std::future run(std::function fn) { auto task = std::make_shared>(std::move(fn)); std::future future = task->get_future(); { std::lock_guard lk(mutex_); tasks_.push([task]() { (*task)(); }); } cv_.notify_one(); return future; } ~ThreadPool() { { std::lock_guard lk(mutex_); stop_ = true; } cv_.notify_all(); for (auto &t : threads_) t.join(); } private: explicit ThreadPool(unsigned n) { for (unsigned i = 0; i < n; ++i) { threads_.emplace_back([this]() { for (;;) { std::function task; { std::unique_lock lk(mutex_); cv_.wait(lk, [this]() { return stop_ || !tasks_.empty(); }); if (stop_ && tasks_.empty()) return; task = std::move(tasks_.front()); tasks_.pop(); } task(); } }); } } std::vector threads_; std::queue> tasks_; std::mutex mutex_; std::condition_variable cv_; bool stop_ = false; }; inline void parallelFor(size_t n, const std::function &fn) { const size_t chunks = std::clamp(std::thread::hardware_concurrency(), 2, 4) + 1; const size_t chunk = (n + chunks - 1) / chunks; if (chunk == 0) return; std::vector> futures; size_t begin = chunk; for (; begin < n; begin += chunk) { futures.push_back(ThreadPool::instance().run([&fn, begin, end = std::min(begin + chunk, n)]() { fn(begin, end); })); } fn(0, std::min(chunk, n)); for (auto &f : futures) f.get(); }