![]() |
Implementation of a thread pool. More...
#include <ThreadPool.h>
Inherits blaze::NonCopyable.
Public Member Functions | |
Constructor | |
ThreadPool (size_t n) | |
Constructor for the ThreadPool class. More... | |
Destructor | |
~ThreadPool () | |
Destructor for the ThreadPool class. More... | |
Get functions | |
bool | isEmpty () const |
Returns whether any tasks are scheduled for execution. More... | |
size_t | size () const |
Returns the current size of the thread pool. More... | |
size_t | active () const |
Returns the number of currently active/busy threads. More... | |
size_t | ready () const |
Returns the number of currently ready/inactive threads. More... | |
Task scheduling | |
template<typename Callable , typename... Args> | |
void | schedule (Callable func, Args &&...args) |
Scheduling the given function/functor for execution. More... | |
Utility functions | |
void | resize (size_t n, bool block=false) |
Changes the total number of threads in the thread pool. More... | |
void | wait () |
Waiting for all scheduled tasks to be completed. More... | |
void | clear () |
Removing all scheduled tasks from the thread pool. More... | |
Private Types | |
typedef Thread< TT, MT, LT, CT > | ManagedThread |
Type of the managed threads. | |
typedef PtrVector< ManagedThread > | Threads |
Type of the thread container. | |
typedef threadpool::TaskQueue | TaskQueue |
Type of the task queue. | |
typedef MT | Mutex |
Type of the mutex. | |
typedef LT | Lock |
Type of a locking object. | |
typedef CT | Condition |
Condition variable type. | |
Private Member Functions | |
Thread functions | |
void | createThread () |
Adding a new thread to the thread pool. More... | |
bool | executeTask () |
Executing a scheduled task. More... | |
Private Attributes | |
Member variables | |
volatile size_t | total_ |
Total number of threads in the thread pool. | |
volatile size_t | expected_ |
Expected number of threads in the thread pool. More... | |
volatile size_t | active_ |
Number of currently active/busy threads. | |
Threads | threads_ |
The threads contained in the thread pool. | |
TaskQueue | taskqueue_ |
Task queue for the scheduled tasks. | |
Mutex | mutex_ |
Synchronization mutex. | |
Condition | waitForTask_ |
Wait condition for idle threads. | |
Condition | waitForThread_ |
Wait condition for the thread management. | |
Implementation of a thread pool.
The ThreadPool class template represents a thread pool according to the thread pool pattern (see for example http://en.wikipedia.org/wiki/Thread_pool_pattern). It manages a certain number of threads in order to process a larger number of independent tasks.
The primary purpose of a thread pool is the reuse of system resources: instead of creating a single thread for every individual task, threads are reused to handle several tasks. This increases the performance in comparison to different threading strategies, as illustrated in the graph below. The first bar indicates the sequential performance of 1000 matrix-matrix multiplications of arbitrarily sized square matrices. The second bar shows the performance of the same work performed by 1000 distinct threads (i.e. one thread for each matrix-matrix multiplication) on a quad-core system. In this case, all cores of the system can be used, but the additional overhead of creating and managing new threads prevents the expected performance increase by a factor of four. The third bar illustrates the performance of four threads distributing the work between them (i.e. 250 matrix-matrix multiplications per thread), again using the same quad-core system. This approach nearly achieves four times the performance of the sequential execution. The fourth bar represents the performance of the ThreadPool class using fourth threads for the execution of the 1000 individual multiplications.
Additionally, the thread pool approach simplifies load balancing and increases the stability of the system.
The implementation of the ThreadPool class template is based on the implementation of standard thread functionality as provided by the C++11 standard or the Boost library. Via the four template parameters it is possible to configure a ThreadPool instance as either a C++11 thread pool or as Boost thread pool:
std::thread
, boost::thread
, or any other standard conforming thread type.std::mutex
, boost::mutex
, or any other standard conforming mutex type.std::unique_lock
, boost::unique_lock
.std::condition_variable
, boost::condition_variable
, or any other standard conforming condition variable type.The following example demonstrates how to configure the ThreadPool class template as either C++11 standard thread pool or as Boost thread pool:
For more information about the standard thread functionality, see [1] or [2] or the current documentation at the Boost homepage: www.boost.org.
The following example demonstrates the use of the ThreadPool class. In contrast to the setup of individual threads (see the Thread class description for more details), it is not necessary to create and manage individual threads, but only to schedules tasks for the accordingly sized thread pool.
Note that the ThreadPool class template schedule() function allows for up to five arguments for the given functions/functors.
It can happen that during the execution of a given task a thread encounters an erroneous situation and has to throw an exception. However, exceptions thrown in the usual way cannot be caught by a try-catch-block in the main thread of execution:
For a detailed explanation how to portably transport exceptions between threads, see [1] or [2]. In case of the Boost library, the according Boost functionality as demonstrated in the following example has to be used. Note that any function/functor scheduled for execution is responsible to handle exceptions in this way!
There is a known issue in Visual Studio 2012 and 2013 that may cause C++11 threads to hang if their destructor is executed after the main()
function:
http://connect.microsoft.com/VisualStudio/feedback/details/747145
In order to circumvent this problem, for Visual Studio compilers only, it is possible to explicitly resize a ThreadPool instance to 0 threads and to block until all threads have been destroyed:
Note that this should ONLY be used before the end of the main()
function and ONLY if the threadpool will not be used anymore.
[1] A. Williams: C++ Concurrency in Action, Manning, 2012, ISBN: 978-1933988771
[2] B. Stroustrup: The C++ Programming Language, Addison-Wesley, 2013, ISBN: 978-0321563842
|
explicit |
Constructor for the ThreadPool class.
n | Initial number of threads ![]() |
This constructor creates a thread pool with initially n new threads. All threads are initially idle until a task is scheduled.
blaze::ThreadPool< TT, MT, LT, CT >::~ThreadPool | ( | ) |
Destructor for the ThreadPool class.
The destructor clears all remaining tasks from the task queue and waits for the currently active threads to complete their tasks.
|
inline |
Returns the number of currently active/busy threads.
void blaze::ThreadPool< TT, MT, LT, CT >::clear | ( | ) |
Removing all scheduled tasks from the thread pool.
This function removes all currently scheduled tasks from the thread pool. The total number of threads remains unchanged and all active threads continue completing their tasks.
|
private |
Adding a new thread to the thread pool.
|
private |
Executing a scheduled task.
This function is repeatedly called by every thread to execute one of the scheduled tasks. In case there is no task available, the thread blocks and waits for a new task to be scheduled.
|
inline |
Returns whether any tasks are scheduled for execution.
|
inline |
Returns the number of currently ready/inactive threads.
void blaze::ThreadPool< TT, MT, LT, CT >::resize | ( | size_t | n, |
bool | block = false |
||
) |
Changes the total number of threads in the thread pool.
n | The new number of threads ![]() |
block | true if the function shall block, false if not. |
std::invalid_argument | Invalid number of threads. |
This function changes the size of the thread pool, i.e. changes the total number of threads contained in the pool. If n is smaller than the current size of the thread pool, the according number of threads is removed from the pool, otherwise new threads are added to the pool. Via the block flag it is possible to block the function until the desired number of threads is available.
Note that there is a known issue in Visual Studio 2012 and 2013 that may cause C++11 threads to hang if their destructor is executed after the main()
function:
http://connect.microsoft.com/VisualStudio/feedback/details/747145
In order to circumvent this problem, for Visual Studio compilers only, it is possible to explicitly resize a ThreadPool instance to 0 threads and to block until all threads have been destroyed:
Note that this should ONLY be used before the end of the main()
function and ONLY if the threadpool will not be used anymore.
void blaze::ThreadPool< TT, MT, LT, CT >::schedule | ( | Callable | func, |
Args &&... | args | ||
) |
Scheduling the given function/functor for execution.
func | The given function/functor. |
args | The arguments for the function/functor. |
This function schedules the given function/functor for execution. The given function/functor must be copyable, must be callable with the given type and number of arguments and must return void
.
|
inline |
Returns the current size of the thread pool.
void blaze::ThreadPool< TT, MT, LT, CT >::wait | ( | ) |
Waiting for all scheduled tasks to be completed.
This function blocks until all scheduled tasks have been completed.
|
private |
Expected number of threads in the thread pool.
This number may differ from the total number of threads during a resize of the thread pool.