1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| #include <atomic> #include <condition_variable> #include <exception> #include <functional> #include <future> #include <memory> #include <mutex> #include <queue> #include <thread> #include <utility> #include <vector>
class ThreadPool final { public: explicit ThreadPool(size_t size); ~ThreadPool() noexcept;
ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; ThreadPool(ThreadPool&&) noexcept = delete; ThreadPool& operator=(ThreadPool&&) noexcept = delete;
template <typename Callable, typename... Args> auto commit(Callable&& f, Args... args) -> std::future<decltype(f(args...))>;
private: void add_thread(size_t size);
private: using Task = std::function<void()>;
size_t m_size; std::vector<std::thread> m_threads;
std::queue<Task> m_tasks; std::mutex m_task_mutex; std::condition_variable m_task_cv;
std::atomic_bool m_running{true}; };
ThreadPool::ThreadPool(size_t size) : m_size(size) { m_threads.reserve(m_size); add_thread(m_size); }
ThreadPool::~ThreadPool() noexcept { m_running = false;
m_task_cv.notify_all(); for (std::thread& thread : m_threads) { if (thread.joinable()) { thread.join(); } } }
template <typename Callable, typename... Args> auto ThreadPool::commit(Callable&& f, Args... args) -> std::future<decltype(f(args...))> { if (!m_running) { std::terminate(); }
using RetType = decltype(f(args...)); auto task = std::make_shared<std::packaged_task<RetType()>>( std::bind(std::forward<Callable>(f), std::forward<Args>(args)...)); std::future<RetType> future = task->get_future(); { std::lock_guard<std::mutex> lock(m_task_mutex); m_tasks.emplace([task] { (*task)(); }); } m_task_cv.notify_one();
return future; }
void ThreadPool::add_thread(size_t size) { auto execute = [this]() -> void { while (true) { Task task; { std::unique_lock<std::mutex> lock(m_task_mutex); m_task_cv.wait(lock, [this]() -> bool { return !m_running || !m_tasks.empty(); }); if (!m_running && m_tasks.empty()) { return; } task = std::move(m_tasks.front()); m_tasks.pop(); }
task(); } };
for (size_t i = 0; i < size; ++i) { m_threads.emplace_back(execute); } }
|