Guest User

Untitled

a guest
Jul 9th, 2025
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.56 KB | None | 0 0
  1.  
  2. using default_func_type = std::move_only_function<void()>;
  3. template <typename FunctionType = default_func_type> requires std::invocable<FunctionType>
  4. class ThreadPool {
  5. public:
  6.     ThreadPool(unsigned int threads_count = std::thread::hardware_concurrency()) {
  7.         m_workers.reserve(threads_count); // Reserve space, avoid reallocations
  8.         for (unsigned int i = 0; i < threads_count; ++i) {
  9.             m_workers.emplace_back([this] {
  10.                 while (true) {
  11.                     std::unique_lock lock{m_mutex};
  12.                     m_condvar.wait(lock, [this]{ return !m_tasks.empty() || !m_should_work.load(std::memory_order_acquire); });
  13.                     if (!m_should_work.load(std::memory_order_acquire)) { // If tasks must be finished, end the loop
  14.                         return;
  15.                     }
  16.                    
  17.                     FunctionType task = std::move(m_tasks.front()); // Get task and run it
  18.                     m_tasks.pop_front();
  19.                     lock.unlock(); // Dont need lock anymore
  20.  
  21.                     task(); // Cant really be broken i suppose
  22.                 }
  23.             });
  24.         }
  25.     }
  26.     ThreadPool(const ThreadPool& rhs) = delete;
  27.     ThreadPool& operator=(const ThreadPool& rhs) = delete;
  28.  
  29.     ~ThreadPool() {
  30.         m_should_work.store(false, std::memory_order_release);
  31.         m_condvar.notify_all();
  32.     }
  33.  
  34.     template<typename Function, typename ... Args, typename ReturnT = std::invoke_result_t<Function, Args...>> requires std::invocable<Function, Args...>
  35.     [[nodiscard]]
  36.     auto enqueue(Function&& function, Args&&... args) -> std::future<ReturnT> {
  37.         std::promise<ReturnT> promise;
  38.         auto future = promise.get_future(); // Make a promise which we will use to return value in a future
  39.         enqueue_task([function = std::forward<Function>(function), promise = std::move(promise), ...args = std::forward<Args>(args)]() mutable {
  40.             try {
  41.                 if constexpr (std::is_same_v<void, std::invoke_result_t<Function, Args...>>) {
  42.                     std::invoke(function, args...);
  43.                 } else {
  44.                     promise.set_value(std::invoke(function, args...));
  45.                 }
  46.             } catch (...) {
  47.                 promise.set_exception(std::current_exception());
  48.             }
  49.         });
  50.         return future;
  51.     }
  52.  
  53.     template<typename Function, typename ... Args> requires std::invocable<Function, Args...>
  54.     void enqueue_detach(Function&& function, Args&&... args) {
  55.         enqueue_task([function = std::forward<Function>(function), ...args = std::forward<Args>(args)]() mutable {
  56.             try {
  57.                 std::invoke(function, args...); // Ignore return value if it is marked with [[nodiscard]]
  58.             } catch (const std::exception& ex) {
  59.                 std::println("Exception in worker: {}", ex.what());
  60.             }
  61.         });
  62.     }
  63.  
  64.  
  65.     void clear() {
  66.         std::unique_lock lock{m_mutex};
  67.         m_tasks.clear();
  68.     }
  69.  
  70.     std::deque<FunctionType>::size_type queue_size() const {
  71.         std::unique_lock lock{m_mutex};
  72.         return m_tasks.size();
  73.     }
  74.  
  75. private:
  76.     void enqueue_task(FunctionType&& task) {
  77.         std::unique_lock lock{m_mutex};
  78.         m_tasks.push_back(std::move(task));
  79.         m_condvar.notify_one();
  80.     }
  81.  
  82.     std::vector<std::jthread> m_workers;
  83.     std::deque<FunctionType> m_tasks; // Deque because we can easily pop_front, back and etc
  84.     std::atomic<bool> m_should_work{true};
  85.     std::condition_variable m_condvar;
  86.     mutable std::mutex m_mutex;
  87. };
Advertisement
Add Comment
Please, Sign In to add comment