General Utility Library for C++14  2.11
Classes | Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
gul14::ThreadPool Class Reference

Detailed Description

A pool of worker threads with a task queue.

A thread pool is created with make_thread_pool(). It immediately starts the desired number of worker threads and keeps them running until the object gets destroyed. Work is given to the pool with the add_task() function in the form of a function object or function pointer. Tasks are stored in a queue and executed in the order they were added. This makes a ThreadPool with a single thread effectively a serial task queue.

Each task is associated with a TaskHandle. This handle is returned by add_task() and can be used to query the status of the task or to remove it from the queue via cancel(). Tasks that are already running cannot be canceled.

auto pool = make_thread_pool(1);
auto task = pool->add_task([]() { return 42; });
while (not task.is_complete())
{
std::cout << "Waiting for task to complete...\n";
sleep(0.1);
}
std::cout << "Task result: " << task.get_result() << "\n";
std::shared_ptr< ThreadPool > make_thread_pool(std::size_t num_threads, std::size_t capacity=ThreadPool::default_capacity)
Create a thread pool with the desired number of threads and the specified capacity for queuing tasks.
Definition: ThreadPool.h:596
bool sleep(const std::chrono::duration< Rep, Period > &duration, const Trigger &trg)
Sleep for at least the given time span, with the option of being woken up from another thread.
Definition: time_util.h:114

Tasks can also be scheduled to start after a specific time point or after a certain delay. Each task can also be given a name, which is mainly useful for debugging. See the example for an introduction.

All public member functions are thread-safe.

On Linux, threads in the pool explicitly block the signals SIGALRM, SIGINT, SIGPIPE, SIGTERM, SIGURG, SIGUSR1, and SIGUSR2. This is done to prevent the threads from terminating the whole process if one of these signals is received.

Since
GUL version 2.11

#include <ThreadPool.h>

Inherits std::enable_shared_from_this< ThreadPool >.

Classes

class  TaskHandle
 A handle for a task that has (or had) been enqueued on a ThreadPool. More...
 

Public Types

using TaskId = std::uint64_t
 A unique identifier for a task.
 
using TimePoint = std::chrono::time_point< std::chrono::system_clock >
 
using Duration = TimePoint::duration
 

Public Member Functions

 ~ThreadPool ()
 Destruct the ThreadPool and join all threads. More...
 
template<typename Function >
TaskHandle< invoke_result_t< Function, ThreadPool & > > add_task (Function fct, TimePoint start_time={}, std::string name={})
 Enqueue a task. More...
 
template<typename Function , std::enable_if_t< is_invocable< Function >::value, bool > = true>
TaskHandle< invoke_result_t< Function > > add_task (Function fct, TimePoint start_time={}, std::string name={})
 
template<typename Function , std::enable_if_t< is_invocable< Function, ThreadPool & >::value, bool > = true>
TaskHandle< invoke_result_t< Function, ThreadPool & > > add_task (Function fct, Duration delay_before_start, std::string name={})
 
template<typename Function , std::enable_if_t< is_invocable< Function >::value, bool > = true>
TaskHandle< invoke_result_t< Function > > add_task (Function fct, Duration delay_before_start, std::string name={})
 
template<typename Function , std::enable_if_t< is_invocable< Function, ThreadPool & >::value, bool > = true>
TaskHandle< invoke_result_t< Function, ThreadPool & > > add_task (Function fct, std::string name)
 
template<typename Function , std::enable_if_t< is_invocable< Function >::value, bool > = true>
TaskHandle< invoke_result_t< Function > > add_task (Function fct, std::string name)
 
GUL_EXPORT std::size_t cancel_pending_tasks ()
 Remove all pending tasks from the queue. More...
 
GUL_EXPORT std::size_t capacity () const noexcept
 Return the maximum number of pending tasks that can be queued.
 
GUL_EXPORT std::size_t count_pending () const
 Return the number of pending tasks.
 
GUL_EXPORT std::size_t count_threads () const noexcept
 Return the number of threads in the pool.
 
GUL_EXPORT std::vector< std::string > get_pending_task_names () const
 Return a vector with the names of the tasks that are waiting to be executed.
 
GUL_EXPORT std::vector< std::string > get_running_task_names () const
 Return a vector with the names of the tasks that are currently running.
 
GUL_EXPORT bool is_full () const noexcept
 Determine whether the queue for pending tasks is full (at capacity).
 
GUL_EXPORT bool is_idle () const
 Return true if the pool has neither pending tasks nor tasks that are currently being executed.
 
GUL_EXPORT bool is_shutdown_requested () const
 Determine whether the thread pool has been requested to shut down.
 

Static Public Member Functions

static GUL_EXPORT std::shared_ptr< ThreadPoolmake_shared (std::size_t num_threads, std::size_t capacity=default_capacity)
 Create a thread pool with the desired number of threads and the specified capacity for enqueuing tasks. More...
 

Static Public Attributes

constexpr static std::size_t default_capacity { 200 }
 Default capacity for the task queue.
 
constexpr static std::size_t max_capacity { 10'000'000 }
 Maximum possible capacity for the task queue.
 
constexpr static std::size_t max_threads { 10'000 }
 Maximum possible number of threads.
 

Constructor & Destructor Documentation

◆ ~ThreadPool()

gul14::ThreadPool::~ThreadPool ( )

Destruct the ThreadPool and join all threads.

This destructor blocks until all threads have terminated. Work that has not yet been started in one of the threads gets canceled, but work that has already been assigned to a thread continues to be executed until it completes.

Member Function Documentation

◆ add_task()

template<typename Function >
TaskHandle<invoke_result_t<Function, ThreadPool&> > gul14::ThreadPool::add_task ( Function  fct,
TimePoint  start_time = {},
std::string  name = {} 
)
inline

Enqueue a task.

There are multiple overloads of this function for variations of the arguments:

Parameters
fctA function object or function pointer to be executed. This function can have an arbitrary return type and may either take no arguments (T fct()) or a reference to the ThreadPool by which it gets executed (T fct(ThreadPool&)).
start_timeEarliest time point at which the task is to be started
nameOptional name for the task (mainly for debugging)
Returns
a TaskHandle that can be used for inquiries about the state of the task and to retrieve its return value.
Exceptions
std::runtime_erroris thrown if the queue is full.
auto pool = make_thread_pool(2); // Create a pool with 2 threads
// A simple task that does not interact with the pool
pool->add_task([]() { std::cout << "Task 1\n"; });
// A task that schedules another task to start two seconds later
pool->add_task(
[](ThreadPool& pool)
{
std::cout << "Task 2\n";
pool.add_task([]() { std::cout << "Task 3\n"; }, 2s);
});
// A task with a name
pool->add_task([]() { std::cout << "Task 4\n"; }, "Task 4");

◆ cancel_pending_tasks()

std::size_t gul14::ThreadPool::cancel_pending_tasks ( )

Remove all pending tasks from the queue.

This call removes all tasks that have not yet been started from the queue. It has no impact on tasks that are currently being executed.

Returns
the number of tasks that were removed.

◆ make_shared()

std::shared_ptr< ThreadPool > gul14::ThreadPool::make_shared ( std::size_t  num_threads,
std::size_t  capacity = default_capacity 
)
static

Create a thread pool with the desired number of threads and the specified capacity for enqueuing tasks.

The thread pool is allocated in a shared pointer, which is necessary so that task handles can access the pool safely. A ThreadPool cannot be constructed directly.

Returns
a shared pointer to the created ThreadPool object.

Referenced by gul14::make_thread_pool().


The documentation for this class was generated from the following files: