patterncppMinor
Platform independant thread pool
Viewed 0 times
platformpoolthreadindependant
Problem
v2 of this question is here and v3 is here
To get a better understanding of C++11/C++14, I thought I would develop a thread pool, even if it has been done to death!
The only dependency outside of the standard library is
threadpool.hpp
```
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include
#include
#include
#include
#include
#include
class threadpool
{
public:
// constructors
//
// calls threadpool(size_t concurrency) with:
//
// concurrency - std::thread::hardware_concurrency()
threadpool();
// calls threadpool(size_t concurrency, size_t queue_size) with:
//
// concurrency - concurrency
// queue_size - 128, arbitary value, should be sufficient for most
// use cases.
threadpool(size_t concurrency);
// creates a threadpool with a specific number of threads and
// a maximum number of queued tasks.
//
// Argument
// concurrency - the guaranteed number of threads used in the
// threadpool, ie. maximum number of tasks worked
// on concurrently.
// queue_size - the maximum number of tasks that can be queued
// for completion, currently running tasks do not
// count towards this total.
threadpool(size_t concurrency, size_t queue_size);
// destructor
//
// Will complete any currently running task as normal, then
// signal to any other tasks that they were not able to run
// through a std::runtime_error exception
~threadpool();
threadpool(const threadpool &) = delete;
threadpool(threadpool &&) = delete;
threadpool & operator=(const threadpool &) = delete;
threadpool & operator=(threadpool &&) = delete;
// run
//
// Runs the given function on one of the thread pool
// threads in First In First Out (FIFO) order
//
// Argument
// task -
To get a better understanding of C++11/C++14, I thought I would develop a thread pool, even if it has been done to death!
The only dependency outside of the standard library is
boost::lockfree::queue.threadpool.hpp
```
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include
#include
#include
#include
#include
#include
class threadpool
{
public:
// constructors
//
// calls threadpool(size_t concurrency) with:
//
// concurrency - std::thread::hardware_concurrency()
threadpool();
// calls threadpool(size_t concurrency, size_t queue_size) with:
//
// concurrency - concurrency
// queue_size - 128, arbitary value, should be sufficient for most
// use cases.
threadpool(size_t concurrency);
// creates a threadpool with a specific number of threads and
// a maximum number of queued tasks.
//
// Argument
// concurrency - the guaranteed number of threads used in the
// threadpool, ie. maximum number of tasks worked
// on concurrently.
// queue_size - the maximum number of tasks that can be queued
// for completion, currently running tasks do not
// count towards this total.
threadpool(size_t concurrency, size_t queue_size);
// destructor
//
// Will complete any currently running task as normal, then
// signal to any other tasks that they were not able to run
// through a std::runtime_error exception
~threadpool();
threadpool(const threadpool &) = delete;
threadpool(threadpool &&) = delete;
threadpool & operator=(const threadpool &) = delete;
threadpool & operator=(threadpool &&) = delete;
// run
//
// Runs the given function on one of the thread pool
// threads in First In First Out (FIFO) order
//
// Argument
// task -
Solution
This does not really stop them spinning:
It may give up the core for another thread (temporarily). But it will come back just as quickly to check for more work. So I am not convinced this actually buys you anything.
I would use a condition variable and block threads on it while there is no work. Then you know they are not taking up any cycles when there is no work.
When creating the work package.
I would forward the task (remember that named variables can not activate move semantics).
// rather than spinning, give up thread time to other things
std::this_thread::yield();It may give up the core for another thread (temporarily). But it will come back just as quickly to check for more work. So I am not convinced this actually buys you anything.
I would use a condition variable and block threads on it while there is no work. Then you know they are not taking up any cycles when there is no work.
When creating the work package.
package->task = task;I would forward the task (remember that named variables can not activate move semantics).
package->task = std::forward>(task);Code Snippets
// rather than spinning, give up thread time to other things
std::this_thread::yield();package->task = task;package->task = std::forward<std::function<void()>>(task);Context
StackExchange Code Review Q#54858, answer score: 4
Revisions (0)
No revisions yet.