82 lines
2.0 KiB
C++
82 lines
2.0 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <condition_variable>
|
|
#include <functional>
|
|
#include <future>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
|
|
|
|
class ThreadPool {
|
|
public:
|
|
static ThreadPool &instance() {
|
|
static ThreadPool pool(std::clamp(std::thread::hardware_concurrency(), 2u, 4u));
|
|
return pool;
|
|
}
|
|
|
|
std::future<void> run(std::function<void()> fn) {
|
|
auto task = std::make_shared<std::packaged_task<void()>>(std::move(fn));
|
|
std::future<void> 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<void()> 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<std::thread> threads_;
|
|
std::queue<std::function<void()>> tasks_;
|
|
std::mutex mutex_;
|
|
std::condition_variable cv_;
|
|
bool stop_ = false;
|
|
};
|
|
|
|
|
|
|
|
inline void parallelFor(size_t n, const std::function<void(size_t begin, size_t end)> &fn) {
|
|
const size_t chunks = std::clamp<size_t>(std::thread::hardware_concurrency(), 2, 4) + 1;
|
|
const size_t chunk = (n + chunks - 1) / chunks;
|
|
if (chunk == 0) return;
|
|
std::vector<std::future<void>> 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();
|
|
}
|