This is copied from my answer to another very similar post:
- Start with maximum number of threads the system can support:
int num_threads = std::thread::hardware_concurrency();
- For an efficient threadpool implementation, once threads are created according to
num_threads
, it’s better not to create new ones, or destroy old ones (by joining). There will be a performance penalty, an it might even make your application go slower than the serial version.
Each C++11 thread should be running in their function with an infinite loop, constantly waiting for new tasks to grab and run.
Here is how to attach such a function to the thread pool:
int num_threads = std::thread::hardware_concurrency(); std::vector<std::thread> threads; for (int i = 0; i < num_threads; i++) { pool.push_back(std::thread(Infinite_loop_function)); }
- The infinite loop function. This is a
while (true)
loop waiting for the task queue.
void Pool::Infinite_loop_function() { while (true) { { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock, [this](){ return !queue.empty() || terminate_pool; }); Job = queue.front(); queue.pop(); } Job(); // function<void()> type } };
- Make a function to add job to your queue
void Pool::Add_Job(function<void()> New_Job) { { std::unique_lock<std::mutex> lock(queue_mutex); queue.push(New_Job); } condition.notify_one(); }
- Bind an arbitrary function to your queue
Pool_Obj.Add_Job(std::bind(&Some_Class::Some_Method, &Some_object));
Once you integrate these ingredients, you have your own dynamic threading pool. These threads always run, waiting for job to do.
I apologize if there are some syntax errors, I typed this code and and I have a bad memory. Sorry that I cannot provide you the complete thread pool code; that would violate my job integrity.
Edit: to terminate the pool, call the shutdown()
method:
Pool::shutdown() { { std::unique_lock<std::mutex> lock(threadpool_mutex); terminate_pool = true; // use this flag in condition.wait } condition.notify_all(); // wake up all threads. // Join all threads. for (std::thread &th : threads) { th.join(); } pool.clear(); stopped = true; // use this flag in destructor, if not set, call shutdown() }
Note: the anonymous code blocks are used so that when they are exited, the std::unique_lock
variables created within them go out of scope, unlocking the mutex.