ImFusion SDK 4.3
ThreadPool Class Reference

#include <ImFusion/Core/Threading/ThreadPool.h>

Lightweight implementation of a thread pool for distributing work onto a fixed number of threads. More...

+ Inheritance diagram for ThreadPool:

Detailed Description

Lightweight implementation of a thread pool for distributing work onto a fixed number of threads.

Internally, ThreadPool will use the StoppableThread interface so that you can abort any work if needed.

Example:

ThreadPool threadPool; // create a thread pool with as many threads as CPU cores available
std::future<int> task = threadPool.enqueue( /* some callable returning an int *&zwj;/ );
int result = task.get(); // wait for the task to complete and get its result
auto enqueue(Function &&func, Args &&... args) -> std::future< ResultOf< Function, Args... > >
Enqueue a single task.
Definition ThreadPool.h:148
ThreadPool(int numThreads=std::max< int >(1, int(std::thread::hardware_concurrency())))
Create a new thread pool using the given number of threads.

Public Types

template<typename F, typename... Args>
using ResultOf = typename std::invoke_result<F, Args...>::type
 

Public Member Functions

 ThreadPool (int numThreads=std::max< int >(1, int(std::thread::hardware_concurrency())))
 Create a new thread pool using the given number of threads.
 
 ~ThreadPool ()
 Implicitly calls cancelTasks() and join() on destruction.
 
template<class Function, class... Args>
auto enqueue (Function &&func, Args &&... args) -> std::future< ResultOf< Function, Args... > >
 Enqueue a single task.
 
template<class CallbackFunc, class Function, class... Args>
void enqueueSignaled (CallbackFunc &&callback, Function &&func, Args &&... args)
 Enqueue a single task and get notified when it has finished.
 
void runOnEachThread (const std::function< void(int)> &func)
 Executes the given function on each thread of the thread pool and blocks until all calls have completed.
 
void cancelTasks ()
 Signal to all tasks that they should abort their execution even if there are still tasks to finish.
 
bool isFinished ()
 Returns whether there are currently no tasks in flight and no tasks waiting.
 
bool waitUntilFinished (std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
 Blocks the current thread until all tasks have finished or the given timeout has been reached.
 
void join ()
 Join all worker threads and wait until all enqueued tasks have finished.
 
int numThreads () const
 Return the number of threads used by this pool.
 
int numWaitingTasks () const
 Return the number of tasks that have not yet been started.
 
int numRunningTasks () const
 Return the number tasks that have been started but did not yet complete.
 
void setThreadNames (const std::string &threadPoolName)
 Sets the name of each worker thread to <threadPoolName> #i so that a debugger may show it as description.
 

Additional Inherited Members

- Protected Member Functions inherited from NotCopyable
 NotCopyable (NotCopyable &&) noexcept=default
 
NotCopyableoperator= (NotCopyable &&) noexcept=default
 
 NotCopyable (const NotCopyable &)=delete
 
NotCopyableoperator= (const NotCopyable &)=delete
 

Member Function Documentation

◆ enqueue()

template<class Function, class... Args>
auto enqueue ( Function && func,
Args &&... args ) -> std::future<ResultOf<Function, Args...>>

Enqueue a single task.

You can either pass a lambda expression or a callable+arguments, for instance:

std::future<double> result1 = threadPool.enqueue([this]() { return this->processItem(1); });
std::future<double> result2 = threadPool.enqueue(MyClass::processItem, this, 2);
// calling std::future::get() will block until the thread has finished computing the result
double sum = result1.get() + result2.get();
T get(T... args)
Parameters
funcCallable object that is to be executed (e.g. a lambda function or a function pointer).
argsOptional arguments to bind to f.
Returns
A future to access the result of the asynchronous operation. It is safe to discard the return value in case you do not want to access the result and do not wait for completion of the operation.
Exceptions
std::runtime_errorif you call this function after calling join().

◆ enqueueSignaled()

template<class CallbackFunc, class Function, class... Args>
void enqueueSignaled ( CallbackFunc && callback,
Function && func,
Args &&... args )

Enqueue a single task and get notified when it has finished.

You can either pass a lambda expression or a callable+arguments, for instance:

threadPool.enqueueSignaled(
[this](Result&& result) {
// do stuff with result, careful: this is executed on the worker thread!
consumeResult(result);
},
[this](item) {
// long running computation that shall be executed on the thread pool
return processItem(item);
});

By design in contrast to enqueue(), this function does not return a future to monitor the progress of the asynchronous operation because callback will already consume its result. In case you need both it is easiest to use enqueue() and to manually call your callback function from within func.

Parameters
callbackCallback function with signature result_of<Function(Args...)>&& -> void to execute when the task has finished. It directly consumes the result of func(args...) by rvalue reference.
Careful: This function is called from the executing thread, make sure to use proper synchronization.
funcCallable object that is to be executed (e.g. a lambda function or a function pointer).
argsOptional arguments to bind to func.
Exceptions
std::runtime_errorif you call this function after calling join().

◆ runOnEachThread()

void runOnEachThread ( const std::function< void(int)> & func)

Executes the given function on each thread of the thread pool and blocks until all calls have completed.

Parameters
funcFunction to execute once on every thread of the pool, its argument indicates the thread index.

◆ cancelTasks()

void cancelTasks ( )

Signal to all tasks that they should abort their execution even if there are still tasks to finish.

Effectively calls StoppableThread::requestStop() on all worker threads and clears the list of pending tasks. This function does not wait until all tasks have been aborted, use waitUntilFinished() to do so.

◆ waitUntilFinished()

bool waitUntilFinished ( std::chrono::milliseconds timeout = std::chrono::milliseconds(0))

Blocks the current thread until all tasks have finished or the given timeout has been reached.

Returns true if all tasks where finished, false otherwise.

Parameters
timeoutMaximum time to wait, ignored if 0.

◆ join()

void join ( )

Join all worker threads and wait until all enqueued tasks have finished.

Note
After calling join() you must not enqueue any more tasks.

◆ setThreadNames()

void setThreadNames ( const std::string & threadPoolName)

Sets the name of each worker thread to <threadPoolName> #i so that a debugger may show it as description.

This functionality is platform-dependent and may not reliably work on all platforms.


The documentation for this class was generated from the following file:
Search Tab / S to search, Esc to close