Guest User

Untitled

a guest
Jan 27th, 2023
21
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.55 KB | None | 0 0
  1. #pragma once
  2.  
  3. namespace Tmpl8
  4. {
  5.  
  6. class ThreadPool; //Forward declare
  7.  
  8. class Worker;
  9.  
  10. class Worker
  11. {
  12.   public:
  13.     //Instantiate the worker class by passing and storing the threadpool as a reference
  14.     Worker(ThreadPool& s) : pool(s) {}
  15.  
  16.     inline void operator()();
  17.  
  18.   private:
  19.     ThreadPool& pool;
  20. };
  21.  
  22. class ThreadPool
  23. {
  24.   public:
  25.     ThreadPool(size_t numThreads) : stop(false)
  26.     {
  27.         for (size_t i = 0; i < numThreads; ++i)
  28.             workers.push_back(std::thread(Worker(*this)));
  29.     }
  30.  
  31.     ~ThreadPool()
  32.     {
  33.         stop = true; // stop all threads
  34.         condition.notify_all();
  35.  
  36.         for (auto& thread : workers)
  37.             thread.join();
  38.     }
  39.  
  40.     template <class T>
  41.     auto enqueue(T task) -> std::future<decltype(task())>
  42.     {
  43.         //Wrap the function in a packaged_task so we can return a future object
  44.         auto wrapper = std::make_shared<std::packaged_task<decltype(task())()>>(std::move(task));
  45.  
  46.         //Scope to restrict critical section
  47.         {
  48.             //lock our queue and add the given task to it
  49.             std::unique_lock<std::mutex> lock(queue_mutex);
  50.  
  51.             tasks.push_back([=] {
  52.                 (*wrapper)();
  53.             });
  54.         }
  55.  
  56.         //Wake up a thread to start this task
  57.         condition.notify_one();
  58.  
  59.         return wrapper->get_future();
  60.     }
  61.  
  62.   private:
  63.     friend class Worker; //Gives access to the private variables of this class
  64.  
  65.     std::vector<std::thread> workers;
  66.     std::deque<std::function<void()>> tasks;
  67.  
  68.     std::condition_variable condition; //Wakes up a thread when work is available
  69.  
  70.     std::mutex queue_mutex; //Lock for our queue
  71.     bool stop = false;
  72. };
  73.  
  74. inline void Worker::operator()()
  75. {
  76.     std::function<void()> task;
  77.     while (true)
  78.     {
  79.         //Scope to restrict critical section
  80.         //This is important because we don't want to hold the lock while executing the task,
  81.         //because that would make it so only one task can be run simultaneously (aka sequantial)
  82.         {
  83.             std::unique_lock<std::mutex> locker(pool.queue_mutex);
  84.  
  85.             //Wait until some work is ready or we are stopping the threadpool
  86.             //Because of spurious wakeups we need to check if there is actually a task available or we are stopping
  87.             pool.condition.wait(locker, [=] { return pool.stop || !pool.tasks.empty(); });
  88.  
  89.             if (pool.stop) break;
  90.  
  91.             task = pool.tasks.front();
  92.             pool.tasks.pop_front();
  93.         }
  94.  
  95.         task();
  96.     }
  97. }
  98.  
  99. } // namespace Tmpl8
Add Comment
Please, Sign In to add comment