UFJF - Machine Learning Toolkit  0.51.8
mltk::ThreadPool Class Reference

A C++17 thread pool class. The user submits tasks to be executed into a queue. Whenever a thread becomes available, it pops a task from the queue and executes it. Each task is automatically assigned a future, which can be used to wait for the task to finish executing and/or obtain its eventual return value. More...

#include <ThreadPool.hpp>

Collaboration diagram for mltk::ThreadPool:

Public Member Functions

 ThreadPool (const ui32 &_thread_count=std::thread::hardware_concurrency())
 Construct a new thread pool. More...
 
 ~ThreadPool ()
 Destruct the thread pool. Waits for all tasks to complete, then destroys all threads. Note that if the variable paused is set to true, then any tasks still in the queue will never be executed. More...
 
ui64 get_tasks_queued () const
 Get the number of tasks currently waiting in the queue to be executed by the threads. More...
 
ui32 get_tasks_running () const
 Get the number of tasks currently being executed by the threads. More...
 
ui32 get_tasks_total () const
 Get the total number of unfinished tasks - either still in the queue, or running in a thread. More...
 
ui32 get_thread_count () const
 Get the number of threads in the pool. More...
 
template<typename T1 , typename T2 , typename F >
void parallelize_loop (const T1 &first_index, const T2 &index_after_last, const F &loop, ui32 num_blocks=0)
 Parallelize a loop by splitting it into blocks, submitting each block separately to the thread pool, and waiting for all blocks to finish executing. The user supplies a loop function, which will be called once per block and should iterate over the block's range. More...
 
template<typename F >
void push_task (const F &task)
 Push a function with no arguments or return value into the task queue. More...
 
template<typename F , typename... A>
void push_task (const F &task, const A &...args)
 Push a function with arguments, but no return value, into the task queue. More...
 
void reset (const ui32 &_thread_count=std::thread::hardware_concurrency())
 Reset the number of threads in the pool. Waits for all currently running tasks to be completed, then destroys all threads in the pool and creates a new thread pool with the new number of threads. Any tasks that were waiting in the queue before the pool was reset will then be executed by the new threads. If the pool was paused before resetting it, the new pool will be paused as well. More...
 
template<typename F , typename... A, typename = std::enable_if_t<std::is_void_v<std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>>>
std::future< bool > submit (const F &task, const A &...args)
 Submit a function with zero or more arguments and no return value into the task queue, and get an std::future<bool> that will be set to true upon completion of the task. More...
 
template<typename F , typename... A, typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>, typename = std::enable_if_t<!std::is_void_v<R>>>
std::future< R > submit (const F &task, const A &...args)
 Submit a function with zero or more arguments and a return value into the task queue, and get a future for its eventual returned value. More...
 
void wait_for_tasks ()
 Wait for tasks to be completed. Normally, this function waits for all tasks, both those that are currently running in the threads and those that are still waiting in the queue. However, if the variable paused is set to true, this function only waits for the currently running tasks (otherwise it would wait forever). To wait for a specific task, use submit() instead, and call the wait() member function of the generated future. More...
 

Public Attributes

std::atomic< bool > paused = false
 An atomic variable indicating to the workers to pause. When set to true, the workers temporarily stop popping new tasks out of the queue, although any tasks already executed will keep running until they are done. Set to false again to resume popping tasks. More...
 
ui32 sleep_duration = 1000
 The duration, in microseconds, that the worker function should sleep for when it cannot find any tasks in the queue. If set to 0, then instead of sleeping, the worker function will execute std::this_thread::yield() if there are no tasks in the queue. The default value is 1000. More...
 

Detailed Description

A C++17 thread pool class. The user submits tasks to be executed into a queue. Whenever a thread becomes available, it pops a task from the queue and executes it. Each task is automatically assigned a future, which can be used to wait for the task to finish executing and/or obtain its eventual return value.

Constructor & Destructor Documentation

◆ ThreadPool()

mltk::ThreadPool::ThreadPool ( const ui32 &  _thread_count = std::thread::hardware_concurrency())
inline

Construct a new thread pool.

Parameters
_thread_countThe number of threads to use. The default value is the total number of hardware threads available, as reported by the implementation. With a hyperthreaded CPU, this will be twice the number of CPU cores. If the argument is zero, the default value will be used instead.

◆ ~ThreadPool()

mltk::ThreadPool::~ThreadPool ( )
inline

Destruct the thread pool. Waits for all tasks to complete, then destroys all threads. Note that if the variable paused is set to true, then any tasks still in the queue will never be executed.

Member Function Documentation

◆ get_tasks_queued()

ui64 mltk::ThreadPool::get_tasks_queued ( ) const
inline

Get the number of tasks currently waiting in the queue to be executed by the threads.

Returns
The number of queued tasks.

◆ get_tasks_running()

ui32 mltk::ThreadPool::get_tasks_running ( ) const
inline

Get the number of tasks currently being executed by the threads.

Returns
The number of running tasks.

◆ get_tasks_total()

ui32 mltk::ThreadPool::get_tasks_total ( ) const
inline

Get the total number of unfinished tasks - either still in the queue, or running in a thread.

Returns
The total number of tasks.

◆ get_thread_count()

ui32 mltk::ThreadPool::get_thread_count ( ) const
inline

Get the number of threads in the pool.

Returns
The number of threads.

◆ parallelize_loop()

template<typename T1 , typename T2 , typename F >
void mltk::ThreadPool::parallelize_loop ( const T1 &  first_index,
const T2 &  index_after_last,
const F &  loop,
ui32  num_blocks = 0 
)
inline

Parallelize a loop by splitting it into blocks, submitting each block separately to the thread pool, and waiting for all blocks to finish executing. The user supplies a loop function, which will be called once per block and should iterate over the block's range.

Template Parameters
T1The type of the first index in the loop. Should be a signed or unsigned integer.
T2The type of the index after the last index in the loop. Should be a signed or unsigned integer. If T1 is not the same as T2, a common type will be automatically inferred.
FThe type of the function to loop through.
Parameters
first_indexThe first index in the loop.
index_after_lastThe index after the last index in the loop. The loop will iterate from first_index to (index_after_last - 1) inclusive. In other words, it will be equivalent to "for (T i = first_index; i < index_after_last; i++)". Note that if first_index == index_after_last, the function will terminate without doing anything.
loopThe function to loop through. Will be called once per block. Should take exactly two arguments: the first index in the block and the index after the last index in the block. loop(start, end) should typically involve a loop of the form "for (T i = start; i < end; i++)".
num_blocksThe maximum number of blocks to split the loop into. The default is to use the number of threads in the pool.

◆ push_task() [1/2]

template<typename F >
void mltk::ThreadPool::push_task ( const F &  task)
inline

Push a function with no arguments or return value into the task queue.

Template Parameters
FThe type of the function.
Parameters
taskThe function to push.

◆ push_task() [2/2]

template<typename F , typename... A>
void mltk::ThreadPool::push_task ( const F &  task,
const A &...  args 
)
inline

Push a function with arguments, but no return value, into the task queue.

The function is wrapped inside a lambda in order to hide the arguments, as the tasks in the queue must be of type std::function<void()>, so they cannot have any arguments or return value. If no arguments are provided, the other overload will be used, in order to avoid the (slight) overhead of using a lambda.

Template Parameters
FThe type of the function.
AThe types of the arguments.
Parameters
taskThe function to push.
argsThe arguments to pass to the function.

◆ reset()

void mltk::ThreadPool::reset ( const ui32 &  _thread_count = std::thread::hardware_concurrency())
inline

Reset the number of threads in the pool. Waits for all currently running tasks to be completed, then destroys all threads in the pool and creates a new thread pool with the new number of threads. Any tasks that were waiting in the queue before the pool was reset will then be executed by the new threads. If the pool was paused before resetting it, the new pool will be paused as well.

Parameters
_thread_countThe number of threads to use. The default value is the total number of hardware threads available, as reported by the implementation. With a hyperthreaded CPU, this will be twice the number of CPU cores. If the argument is zero, the default value will be used instead.

◆ submit() [1/2]

template<typename F , typename... A, typename = std::enable_if_t<std::is_void_v<std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>>>
std::future<bool> mltk::ThreadPool::submit ( const F &  task,
const A &...  args 
)
inline

Submit a function with zero or more arguments and no return value into the task queue, and get an std::future<bool> that will be set to true upon completion of the task.

Template Parameters
FThe type of the function.
AThe types of the zero or more arguments to pass to the function.
Parameters
taskThe function to submit.
argsThe zero or more arguments to pass to the function.
Returns
A future to be used later to check if the function has finished its execution.

◆ submit() [2/2]

template<typename F , typename... A, typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>, typename = std::enable_if_t<!std::is_void_v<R>>>
std::future<R> mltk::ThreadPool::submit ( const F &  task,
const A &...  args 
)
inline

Submit a function with zero or more arguments and a return value into the task queue, and get a future for its eventual returned value.

Template Parameters
FThe type of the function.
AThe types of the zero or more arguments to pass to the function.
RThe return type of the function.
Parameters
taskThe function to submit.
argsThe zero or more arguments to pass to the function.
Returns
A future to be used later to obtain the function's returned value, waiting for it to finish its execution if needed.

◆ wait_for_tasks()

void mltk::ThreadPool::wait_for_tasks ( )
inline

Wait for tasks to be completed. Normally, this function waits for all tasks, both those that are currently running in the threads and those that are still waiting in the queue. However, if the variable paused is set to true, this function only waits for the currently running tasks (otherwise it would wait forever). To wait for a specific task, use submit() instead, and call the wait() member function of the generated future.

Member Data Documentation

◆ paused

std::atomic<bool> mltk::ThreadPool::paused = false

An atomic variable indicating to the workers to pause. When set to true, the workers temporarily stop popping new tasks out of the queue, although any tasks already executed will keep running until they are done. Set to false again to resume popping tasks.

◆ sleep_duration

ui32 mltk::ThreadPool::sleep_duration = 1000

The duration, in microseconds, that the worker function should sleep for when it cannot find any tasks in the queue. If set to 0, then instead of sleeping, the worker function will execute std::this_thread::yield() if there are no tasks in the queue. The default value is 1000.


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