License : Creative Commons Attribution 4.0 International (CC BY-NC-SA 4.0)
Copyright :
Frédéric Pennerath,
CentraleSupelec
Last modified : April 19, 2024 10:22
Link to the source : threads.md
Download thread_pool.zip and generate a suitable build environment using CMake
:
unzip thread_pool.zip ; cd thread_pool
mkdir build ; cd build
cmake ../src
make
./pool_test 1 # Nothing happens as nothing has been implemented yet
The code to edit is in subdirectory src
. The subdirectory solution
contains a possible solution.
This labwork is about the synchronization of C++11 threads based on mutexes and condition variables to handle problems of race condition, deadlock, etc. The goal of the labwork is to design a thread pool.
When a parallelizable computation is short, the fixed time (overhead) required to create and destroy threads and their resources (stack, thread-local variables, etc) is no longer negligible. One solution is to use a thread pool. When it is created, the pool is “filled” with a certain number of threads which are kept on standby. Every time a computational task is posted to the pool, an available thread is woken up and processes the task before going back to sleep once the computation is complete. To handle the case where all the threads are busy, the pool also has a queue storing the computations waiting to be run. The threads in the pool are kept alive as long as the pool itself is not destroyed. A pool is destroyed only once all the ongoing tasks are complete.
We would like to be able to program the thread pool as follows:
void A() { // Run a computation for 100ms ... }
void B() { // Run a computation for 200ms ... }
void C() { // Run a computation for 100ms ... }
{
ThreadPool pool{2}; // Create a thread pool of two threads
pool(A); // Run function A in thread 1 of the pool
pool(B); // Run function B in thread 2 of the pool
pool(C); // Run function C in thread 1 of the pool after 100ms (once thread 1 has finished to run A)
}
// The pool is destroyed here, uniquely when all tasks have been completed, that is after 200ms
ThreadPool
in the ThreadPool.hpp
and ThreadPool.cpp
files to conform to the previous example. Test using function test1
.std::function<void ()>
std::deque
(as inserting/removing elements at the front or back is done in constant time).We want to compare the performance of a thread pool against the “classic” instantiation of threads. To do this we need a join
method that puts the calling thread on hold as long as the pool has a task to process or is being processed, as in the following example.
ThreadPool pool{2}; // Create a thread pool of two threads
pool(A)(B)(C); // Run functions A, B and C
pool.join(); // Wait until A, B and C are completed
join
of class ThreadPool
and evaluate the performance of the thread pool using function test2
.