Class ThreadPool

Class Documentation

class ThreadPool

A fast, lightweight, and easy-to-use C++17 thread pool class. This is a lighter version of the main thread pool class.

Public Functions

inline ThreadPool(const concurrency_t thread_count_ = 0)

Construct a new thread pool.

Parameters

thread_count_ – The number of threads to use. The default value is the total number of hardware threads available, as reported by the implementation. This is usually determined by the number of cores in the CPU. If a core is hyperthreaded, it will count as two threads.

inline ~ThreadPool()

Destruct the thread pool. Waits for all tasks to complete, then destroys all threads.

inline concurrency_t get_thread_count() const

Get the number of threads in the pool.

Returns

The number of threads.

template<typename F, typename T1, typename T2, typename T = std::common_type_t<T1, T2>>
inline void push_loop(T1 first_index_, T2 index_after_last_, F &&loop, size_t num_blocks = 0)

Parallelize a loop by automatically splitting it into blocks and submitting each block separately to the queue. The user must use wait_for_tasks() or some other method to ensure that the loop finishes executing, otherwise bad things will happen.

Template Parameters
  • F – The type of the function to loop through.

  • T1 – The type of the first index in the loop. Should be a signed or unsigned integer.

  • T2 – The 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.

  • T – The common type of T1 and T2.

Parameters
  • first_index_ – The first index in the loop.

  • index_after_last_ – The 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 index_after_last == first_index, no blocks will be submitted.

  • loop – The 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_blocks – The maximum number of blocks to split the loop into. The default is to use the number of threads in the pool.

template<typename F, typename T>
inline void push_loop(const T index_after_last, F &&loop, const size_t num_blocks = 0)

Parallelize a loop by automatically splitting it into blocks and submitting each block separately to the queue. The user must use wait_for_tasks() or some other method to ensure that the loop finishes executing, otherwise bad things will happen. This overload is used for the special case where the first index is 0.

Template Parameters
  • F – The type of the function to loop through.

  • T – The type of the loop indices. Should be a signed or unsigned integer.

Parameters
  • index_after_last – The index after the last index in the loop. The loop will iterate from 0 to (index_after_last - 1) inclusive. In other words, it will be equivalent to “for (T i = 0; i < index_after_last; ++i)”. Note that if index_after_last == 0, no blocks will be submitted.

  • loop – The 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_blocks – The maximum number of blocks to split the loop into. The default is to use the number of threads in the pool.

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

Push a function with zero or more arguments, but no return value, into the task queue. Does not return a future, so the user must use wait_for_tasks() or some other method to ensure that the task finishes executing, otherwise bad things will happen.

Template Parameters
  • F – The type of the function.

  • A – The types of the arguments.

Parameters
  • task – The function to push.

  • args – The zero or more arguments to pass to the function. Note that if the task is a class member function, the first argument must be a pointer to the object, i.e. &object (or this), followed by the actual arguments.

template<typename F, typename ...A, typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
inline std::future<R> submit(F &&task, A&&... args)

Submit a function with zero or more arguments into the task queue. If the function has a return value, get a future for the eventual returned value. If the function has no return value, get an std::future<void> which can be used to wait until the task finishes.

Template Parameters
  • F – The type of the function.

  • A – The types of the zero or more arguments to pass to the function.

  • R – The return type of the function (can be void).

Parameters
  • task – The function to submit.

  • args – The zero or more arguments to pass to the function. Note that if the task is a class member function, the first argument must be a pointer to the object, i.e. &object (or this), followed by the actual arguments.

Returns

A future to be used later to wait for the function to finish executing and/or obtain its returned value if it has one.

inline 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. Note: To wait for just one specific task, use submit() instead, and call the wait() member function of the generated future.