Published December 20, 2024
| Version v5.0.0
Software
Open
A C++17 Thread Pool for High-Performance Scientific Computing
Creators
Description
v5.0.0 (2024-12-19)
- A major new release with many new features, improvements, bug fixes, and performance optimizations! Please note that code written using previous releases may need to be modified to work with the new release. The changes needed to migrate to the new API are explicitly indicated below for your convenience.
- Highlights:
- Added support for C++20 and C++23, while maintaining full C++17 compatibility. In C++20, the library can now optionally be imported as a module using
import BS.thread_pool
on Clang, GCC, and MSVC. In C++23, both the library itself and the test program can now optionally import the C++ Standard Library as a module usingimport std
on supported compilers and platforms. Extensive documentation has been added toREADME.md
on how to use these features, to ease the transition. - Optional features are now enabled via a bitmask template parameter instead of macros, using the flags
BS::tp::priority
,BS::tp::pause
, andBS::tp::wait_deadlock_checks
. This makes the optional features easier to use, allows multiple thread pools with different features to coexist, and makes the library compatible with C++20 modules. Exception handling is now disabled automatically if exceptions are disabled, instead of using a macro. - Added optional native extensions for non-portable features using the operating system's native API: setting the priority and affinity for processes and threads, and setting thread names. These have been tested on the latest versions of Windows, Ubuntu, and macOS.
- This library is now back to being a true single-header library, with a single header file
BS_thread_pool.hpp
. The utility classes have been combined into the main header file.BS::timer
has been removed,BS::signaller
has been replaced withBS::binary_semaphore
andBS::counting_semaphore
(in C++17 mode only), andBS::synced_stream
now supports multiple output streams. - Cleanup functions can now be defined to complement the initialization functions. Both initialization and cleanup functions can now optionally take the index of the thread as an argument.
- Parallelization member functions no longer need type casting or template parameters if the start and end indices are of different types.
- The worker function no longer incorrectly reads shared variables while the mutex is unlocked.
- The type aliases
BS::this_thread::optional_index
andBS::this_thread::optional_pool
have been removed. Instead,BS::this_thread::get_index()
returnsstd::optional<std::size_t>
, andBS::this_thread::get_pool()
returnsstd::optional<void*>
. The latter must be cast to the correct instantiation of theBS::thread_pool
class template before using any member functions. - The thread pool version is now accessible using the object
BS::thread_pool_version
, aconstexpr struct
of typeBS::version
with the membersmajor
,minor
, andpatch
. This works even if importing the library as a C++20 module, unlike the version macros. - The type
priority_t
, used to set priorities, is now defined asstd::int8_t
, which means it takes values from -128 to +127. The pre-defined priorities inBS::pr
, such asBS::pr::highest
orBS::pr::lowest
, have been updated accordingly. - Exceptions thrown by detached tasks are now caught and prevented from propagating, so that they do not terminate the program. Exceptions thrown by submitted tasks are still rethrown when calling
get()
on the future, as before. - Parallelization member functions no longer destruct objects prematurely under certain circumstances.
- The test program has been expanded with many new tests for both old and new features. It can also import both the thread pool module using
import BS.thread_pool
(in C++20 and later) and the C++ Standard Library module usingimport std
(in C++23) if the appropriate macros are defined, and read default command line arguments from adefault_args.txt
file for debugging purposes. - Added new and improved benchmarks using a highly-optimized multithreaded algorithm which generates a plot of the Mandelbrot set, utilizing a normalized iteration count algorithm and linear interpolation to create smooth coloring.
- The type
BS::concurrency_t
has been removed; usestd::size_t
instead.
- Added support for C++20 and C++23, while maintaining full C++17 compatibility. In C++20, the library can now optionally be imported as a module using
- C++20 and C++23 support:
- This library now officially supports C++20 and C++23 in addition to C++17. If compiled with C++20 and/or C++23 support (e.g. using the compiler flag
-std=c++23
in Clang/GCC or/std:c++latest
on MSVC), the library will make use of newly available features for maximum performance, reliability, and usability.- To be clear, the library is still fully compatible with any C++17 standard-compliant compiler. I have no plans to remove C++17 support at the moment, as it is still the most widely used C++ standard among developers, but that might change in the future.
- If C++20 features are available, the library can be imported as a module using
import BS.thread_pool
. This is now the officially recommended way to use the library, as it has many benefits, such as faster compilation times, better encapsulation, no namespace pollution, no include order issues, easier maintainability, simpler dependency management, and more.- The module file itself is
BS.thread_pool.cppm
, located in themodules
folder, and it is just a thin wrapper around the header fileBS_thread_pool.hpp
. - The
constexpr
flagBS::thread_pool_module
indicates whether the thread pool library was compiled as a module. - To my knowledge,
BS::thread_pool
is one of the only popular C++ libraries that are currently available as a C++20 module (and certainly the only thread pool library). This feature has been tested with the latest versions of Clang, GCC, and MSVC. Unfortunately, C++20 modules are still (4 years later!) not fully implemented in all compilers, and each compiler implements them differently; for instructions on how to compile and import theBS.thread_pool
module in each compiler, please seeREADME.md
. - Known issues:
- GCC v14.2.0 (latest version at the time of writing) appears to have an internal compiler error when compiling programs containing modules (or at least, this particular module) with any optimization flags other than
-Og
enabled. Until this is fixed, if you wish to use compiler optimizations, please either include the library as a header file or use a different compiler. - On macOS, Apple Clang v16.0.0 (latest version at the time of writing) does not support C++20 modules. Please either install the latest version of LLVM Clang using Homebrew, or include the library as a header file.
- Visual Studio Code's C/C++ extension v1.23.2 (latest version at the time of writing) does not yet support modules. My temporary solution for that, as demonstrated in the test program, is to define the macro
BS_THREAD_POOL_TEST_IMPORT_MODULE
(see below) when compiling the test program, but not when editing in the IDE. If the macro is enabled, the module is imported viaimport BS.thread_pool
, otherwise the header file is included using#include "BS_thread_pool.hpp"
as usual.
- GCC v14.2.0 (latest version at the time of writing) appears to have an internal compiler error when compiling programs containing modules (or at least, this particular module) with any optimization flags other than
- The module file itself is
- If C++23 features are available, both the library and the test program can now import the C++ Standard Library as a module using
import std
. To enable this, define the macroBS_THREAD_POOL_IMPORT_STD
at compilation time. This is currently only officially supported by recent versions of MSVC with Microsoft STL or LLVM Clang (not Apple Clang) with LLVM libc++. It is not supported by GCC with any standard library, Clang with any standard library other than libc++, any compiler with GNU libstdc++, or any other compiler.- If
BS_THREAD_POOL_IMPORT_STD
is defined, then you must also import the library itself as a module. If the library is included as a header file, this will force the program that included the header file to also importstd
, which is not desirable and can lead to compilation errors if the program#include
s any Standard Library header files. - Defining the macro before importing the module will not work, as modules cannot access macros defined in the program that imported them. Instead, define the macro as a compiler flag, e.g.
-D BS_THREAD_POOL_IMPORT_STD
(or/D
for MSVC). - The
constexpr
flagBS::thread_pool_import_std
indicates whether the thread pool library was compiled withimport std
. Note that the flag will befalse
ifBS_THREAD_POOL_IMPORT_STD
is defined but the compiler or standard library does not support importing the C++ Standard Library as a module.
- If
- If C++20 features are available, the pool will use
std::jthread
instead ofstd::thread
. This allows considerable simplification and added safety, since the threads no longer need to be manually joined, andstd::stop_token
is used to stop the workers automatically when destructing the threads. This eliminates the need for thedestroy_threads()
member function, as well as theworkers_running
flag, which are now only used in C++17 mode. - If C++20 features are available, the library will use concepts to enforce the signature of the initialization function and to selectively enable member functions related to pausing only if pausing is enabled. In C++17 mode, the library will use SFINAE to achieve essentially the same effect.
- If C++23 features are available, the task queue will use
std::move_only_function<void()>
instead ofstd::function<void()>
. This allowssubmit_task()
to work without using a shared pointer, which should increase performance. - API migration: All of the C++20/C++23 features listed above are either automatically applied based on compiler settings or optional. If you are still using C++17, or if you are using C++20 or C++23 but do not wish to import the thread pool library and/or the C++ Standard Library as a module, no changes are needed.
- This library now officially supports C++20 and C++23 in addition to C++17. If compiled with C++20 and/or C++23 support (e.g. using the compiler flag
- Optional features overhaul:
- All optional features are now enabled via a bitmask template parameter instead of macros. This works using
if constexpr
,std::conditional_t
, and concepts (in C++20 and later) or SFINAE (in C++17).- This change makes the optional features much easier and more intuitive to use, as you no longer need to define any macros before including the header file.
- Additionally, it allows you to have multiple thread pools in the same program with different optional features enabled or disabled. For example, you can have one pool with task priority enabled and another without.
- Most importantly, this makes it possible to import the library as a C++20 module, as macros cannot be read by imported modules.
- The bitmask flags are members of the
BS::tp
enumeration:BS::tp::priority
enables task priority (previously enabled via the macroBS_THREAD_POOL_ENABLE_PRIORITY
, which has been removed).BS::tp::pause
enables pausing the pool (previously enabled via the macroBS_THREAD_POOL_ENABLE_PAUSE
, which has been removed).BS::tp::wait_deadlock_checks
enables deadlock checks inwait()
/wait_for()
/wait_until()
(previously enabled via the macroBS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK
, which has been removed).- The default is
BS::tp::none
, which disables all optional features.
- Convenience aliases are defined as follows:
BS::light_thread_pool
disables all optional features (equivalent toBS::thread_pool
with the default template parameter, that is,BS::thread_pool<BS::tp::none>
).BS::priority_thread_pool
enables task priority (equivalent toBS::thread_pool<BS::tp::priority>
).BS::pause_thread_pool
enables pausing the pool (equivalent toBS::thread_pool<BS::tp::pause>
).BS::wdc_thread_pool
enables wait deadlock checks (equivalent toBS::thread_pool<BS::tp::wait_deadlock_checks>
).- There are no aliases with multiple features enabled; if this is desired, you must either pass the template parameter explicitly or define your own alias. Note that the parameter is a bitmask, so to enable multiple features, you need to use the bitwise OR operator
|
, e.g.BS::thread_pool<BS::tp::priority | BS::tp::pause>
to enable both task priority and pausing.
- The macro
BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING
has been removed. Exception handling is disabled automatically if exceptions are disabled, based on whether the feature-test macro__cpp_exceptions
is defined. - The exception thrown by wait deadlock checks is now
BS::wait_deadlock
instead ofBS::thread_pool::wait_deadlock
, to avoid having to deal with different template parameters. - The macro
BS_THREAD_POOL_LIGHT_TEST
has been removed from the test program, as all optional features are now tested by enabling them selectively via the template parameter, so there is no need to compile with different macros. - If for some reason you forgot which options you enabled when creating the pool, the
static constexpr
memberspriority_enabled
,pause_enabled
, andwait_deadlock_checks_enabled
can be used to check if the corresponding features are enabled. - API migration:
BS::thread_pool
can still be used without the template parameter, for backwards compatibility; this will create a thread pool with all optional features disabled. Therefore, if you did not use any of the optional features in existing code, no changes are needed.- If your code uses any of the optional features by defining macros before including the header file, please remove these macros, and instead either use one of the convenience aliases above or define the template parameter explicitly using the
BS::tp
enumeration when creating the pool. - If you use wait deadlock checks, you must now catch the exception
BS::wait_deadlock
instead ofBS::thread_pool::wait_deadlock
.
- All optional features are now enabled via a bitmask template parameter instead of macros. This works using
- Native extensions:
- While portability is one of my guiding principle when developing this library, non-portable features such as setting the thread priority using the operating system's native API are frequently requested by users. Starting with this release, the library includes native extensions, which are disabled by default.
- Currently, the extensions provide the following functions (please see
README.md
for details on how to use them):BS::get_os_process_affinity()
andBS::set_os_process_affinity()
to get and set the CPU affinity of the current process in a portable way. Should work on Windows and Linux, but not on macOS, as the native API does not allow it.BS::get_os_process_priority()
andBS::set_os_process_priority()
to get and set the priority of the current process in a portable way. Should work on Windows, Linux, and macOS.BS::this_thread::get_os_thread_affinity()
andBS::this_thread::set_os_thread_affinity()
to get and set the CPU affinity of the current thread in a portable way. Should work on Windows and Linux, but not on macOS, as the native API does not allow it.BS::this_thread::get_os_thread_priority()
andBS::this_thread::set_os_thread_priority()
to get and set the priority of the current thread in a portable way. Should work on Windows, Linux, and macOS.BS::this_thread::get_os_thread_name()
andBS::this_thread::set_os_thread_name()
to get and set the name of the current thread in a portable way, for debugging purposes. Should work on Windows, Linux, and macOS.
- The native extensions may be enabled by defining the macro
BS_THREAD_POOL_NATIVE_EXTENSIONS
at compilation time.- Even if the macro is defined, the extensions are disabled automatically if a supported operating system (Windows, Linux, or macOS) is not detected.
- Note that if you are using the library as a C++20 module, defining the macro before importing the module will not work, as modules cannot access macros defined in the program that imported them. Instead, define the macro as a compiler flag, e.g.
-D BS_THREAD_POOL_NATIVE_EXTENSIONS
(or/D
for MSVC).
- The macro
BS_THREAD_POOL_ENABLE_NATIVE_HANDLES
has been removed. The thread pool member functionget_native_handles()
is now part of the native extensions, so it is enabled using the macroBS_THREAD_POOL_NATIVE_EXTENSIONS
. - Please note that the native extensions have only been tested on Windows 11 23H2, Ubuntu 24.10, and macOS 15.1. They have not been tested on older versions of these operating systems, other Linux distributions, or any other operating systems, and are therefore not guaranteed to work on every system. If you encounter any issues, please report them on the GitHub repository.
- The test program only tests the native extensions if the macro
BS_THREAD_POOL_NATIVE_EXTENSIONS
is defined at compilation time. If importing the library as a module, please ensure that the macro is also enabled when compiling the module. - The
constexpr
flagBS::thread_pool_native_extensions
indicates whether the thread pool library was compiled with native extensions enabled. Note that the flag will befalse
ifBS_THREAD_POOL_NATIVE_EXTENSIONS
is defined but the operating system is unsupported. - API migration: The native extensions are a brand new optional feature and do not require any changes to existing code.
- Utility classes:
- This library is now back to being a true single-header library, with a single header file
BS_thread_pool.hpp
. The utility classes (previously in a separate headerBS_thread_pool_utils.hpp
, which has been removed) have been combined into the main header file. - The
BS::timer
class has been removed from the library, since it doesn't really have anything to do with multithreading directly. However, it is still available in the test program if you want to use it. - The
BS::signaller
class has been removed from the library, and replaced withBS::binary_semaphore
andBS::counting_semaphore
, which are C++17 polyfills for the C++20 classesstd::binary_semaphore
andstd::counting_semaphore
. If C++20 features are available, the polyfills are not used, and instead are just aliases for the standard library classes. The reason is that semaphores can do the same thing that the signaller class was previously used for, but are much more versatile. - The
BS::synced_stream
class now supports printing to more than one output stream. - API migration:
- If you previously included the
BS_thread_pool_utils.hpp
header file, this is no longer needed. Only include the headerBS_thread_pool.hpp
, or better yet, in C++20 or later, import the library as a module usingimport BS.thread_pool
. - If you previously used the
BS::timer
class, it is no longer available in the header file, but if you still need it you can copy it into your program directly from the test programBS_thread_pool_test.cpp
. - If you previously used the
BS::signaller
class, you can replace it withBS::binary_semaphore
orBS::counting_semaphore
. Previously, you defined an objectBS::signaller signal
, and then usedsignal.wait()
to wait for the signal, andsignal.ready()
to unblock all waiting threads. Now, you can define an objectBS::counting_semaphore signal(0)
, and usesignal.acquire()
to wait for the signal, andsignal.release(num_threads)
to unblock waiting threads; note that the number of threads to release must be passed explicitly, as the semaphore also allows you to unblock only some of them. UseBS::binary_semaphore
if only one thread will be waiting at any given time. - If you previously used the
BS::synced_stream
class, no changes are needed.
- If you previously included the
- This library is now back to being a true single-header library, with a single header file
- Cleanup and initialization functions:
- Using the new
set_cleanup_func()
member function, it is now possible to provide the pool with a cleanup function to run in each thread right before it is destroyed, which will happen when the pool is destructed or reset. See #152. - Both initialization and cleanup functions can now optionally take the index of the thread as an argument.
- Added a warning in the documentation that both initialization and cleanup functions must not throw any exceptions, as that will result in program termination. Any exceptions must be handled explicitly within the function.
- API migration: No changes to existing code are needed.
- Using the new
- Parallelization index types:
- All member functions which parallelize collections of tasks, namely
detach_blocks()
,detach_loop()
,detach_sequence()
,submit_blocks()
,submit_loop()
, andsubmit_sequence()
, can now be called with start and end indices of different types. - Previously, the indices had to be of the same type, or the template parameter had to be explicitly specified; this is no longer needed, as the library will automatically cast the indices to a suitable common type.
- This was already possible in v2.X.X and v3.X.X, where it was done using
std::common_type
, but I removed it in v4.X.X becausestd::common_type
sometimes completely messed up the range of the loop. For example, thestd::common_type
ofint
andunsigned int
isunsigned int
, which means the loop will only use non-negative indices even if theint
start index was negative, resulting in an integer overflow. - Starting with v5.0.0, the library uses a custom type trait
BS::common_index_type
to determine the common type of the indices. The common type of two signed integers or two unsigned integers is the larger of the integers, while the common type of a signed and an unsigned integer is a signed integer that can hold the full ranges of both integers. This avoids messing up the indices, except in the case ofstd::uint64_t
, where there is no fundamental signed type that can hold its entire range. In this case, we choosestd::uint64_t
as the common type, since the most common use case is where the indices go from 0 tox
wherex
has been previously defined asstd::size_t
. This will fail if the first index is negative; in that case, the user must cast the indices explicitly. - API migration: Existing code which uses type casting or explicit template parameters in parallelization functions does not need to be changed, but it can be simplified by removing the casting or template parameters. However, if one index is negative and the other is an unsigned 64-bit integer, casting is still needed (although you should probably not be doing this in the first place, as casting to either of the two types will result in potential narrowing or overflow).
- All member functions which parallelize collections of tasks, namely
BS::this_thread
:BS::this_thread
is now a class instead of a namespace, since defining it as a namespace proved to be incompatible with C++20 modules (at least in some compilers). Defining it as a class also results in a simpler implementation. However, the functionality remains the same, and since it only has static methods, the call syntax forBS::this_thread::get_index()
andBS::this_thread::get_pool()
is unchanged.- The type aliases
BS::this_thread::optional_index
andBS::this_thread::optional_pool
have been removed. Instead,BS::this_thread::get_index()
now returns the explicit typestd::optional<std::size_t>
, andBS::this_thread::get_pool()
returnsstd::optional<void*>
.- The rationale for this removal is that using
std::optional
explicitly provides more information about the type that is being returned, and most users are probably not using the explicit types anyway (either by usingauto
or by invoking thestd::optional
member functions directly on the returned object).
- The rationale for this removal is that using
- Note that
BS::this_thread::get_pool()
now returns an optionalvoid*
instead ofBS::thread_pool*
. The reason for that is thatBS::thread_pool
is now a template. Once you obtain the pool pointer, you must cast it to the desired instantiation of the template if you want to use any member functions. Note that you have to cast it to the correct type; if you cast a pointer to aBS::light_thread_pool
into a pointer to aBS::priority_thread_pool
, for example, your program will have undefined behavior. - API migration:
- If your code uses the type aliases, please replace
BS::this_thread::optional_index
withstd::optional<std::size_t>
andBS::this_thread::optional_pool
withstd::optional<void*>
. - If your code uses
BS::this_thread::get_pool()
, you must now cast the returned pointer to the correct instantiation of theBS::thread_pool
class template before using any member functions.
- If your code uses the type aliases, please replace
- Determining the library version:
- The library now defines the
constexpr
objectBS::thread_pool_version
, which can be used to check the version of the library at compilation time. This object is of typeBS::version
, with membersmajor
,minor
, andpatch
, and all comparison operators defined asconstexpr
. It also has ato_string()
member function and anoperator<<
overload for easy printing at runtime. For example, you can dostatic_assert(BS::thread_pool_version == BS::version(5, 0, 0))
, or you can use it inif constexpr
for conditional compilation. - The version macros
BS_THREAD_POOL_VERSION_MAJOR
,BS_THREAD_POOL_VERSION_MINOR
, andBS_THREAD_POOL_VERSION_PATCH
are still defined, since they can be used in conditional code inclusion, and for backwards compatibility. However, since C++20 modules cannot export macros,BS::thread_pool_version
is the only way to check the version of the thread pool library if you are importing it as a module. - API migration: No changes needed in existing code; if you previously used the macros
BS_THREAD_POOL_VERSION_MAJOR
,BS_THREAD_POOL_VERSION_MINOR
, andBS_THREAD_POOL_VERSION_PATCH
to determine the version of the library when including it as a header file, you can still do so. However, if you wish to import the library as a C++20 module, you must use the objectBS::thread_pool_version
instead.
- The library now defines the
- Task priority:
- The type
priority_t
, used to set priorities, is now defined asstd::int8_t
, which means it takes values from -128 to +127. The pre-defined priorities inBS::pr
, such asBS::pr::highest
orBS::pr::lowest
, have been updated accordingly (also, it is now anenum
instead of a namespace). The old priority typestd::int16_t
was unnecessarily large; having fewer priority values means less bookkeeping in the priority queue, which should also improve performance. - API migration: If you used the pre-defined priorities in
BS::pr
, no changes are needed. If you specified numerical priorities directly, you may need to adjust them to the new range of -128 to +127.
- The type
- Miscellaneous:
- Exceptions thrown by detached tasks are now caught and prevented from propagating, so that they do not terminate the program. Exceptions thrown by submitted tasks are still rethrown when calling
get()
on the future, as before. - All member functions which parallelize collections of tasks, namely
detach_blocks()
,detach_loop()
,detach_sequence()
,submit_blocks()
,submit_loop()
, andsubmit_sequence()
, now store the callable object inside anstd::shared_ptr
, and then pass that shared pointer to each subtask. Previously, the callable was passed using perfect forwarding, which under some circumstances resulted in mistakenly moving the callable during the first iteration of the loop, thus potentially destructing captured objects prematurely. The new shared pointer method resolves this issue, while also avoiding making copies of the callable. See #149. - Fixed incorrect reading of shared variables while the mutex is unlocked in the worker function. See #159.
- Added documentation to
README.md
for all the new features. In addition, fixed some typos and other minor issues in the existing documentation. - Added instructions in
README.md
for installing the library using CMake withFetchContent
instead of CPM. See #155. - The type
BS::concurrency_t
has been removed. In previous versions this type was defined to be the type of the value returned bystd::thread::hardware_concurrency()
(which is supposed to beunsigned int
), for maximum portability. However, in practice this value is only used to indicate the size of arrays, sostd::size_t
is more appropriate, and this simplifies the code. - API migration: If you used
BS::concurrency_t
in your code, please replace it withstd::size_t
. If you previously cast to/from these two types, you can now remove the cast.
- Exceptions thrown by detached tasks are now caught and prevented from propagating, so that they do not terminate the program. Exceptions thrown by submitted tasks are still rethrown when calling
- Tests:
- The test program
BS_thread_pool_test.cpp
will import the library as a C++20 module viaimport BS.thread_pool
if the macroBS_THREAD_POOL_TEST_IMPORT_MODULE
is defined, C++20 or later is detected, and a supported compiler is used. - The test program will also import the C++ Standard Library as a module using
import std
if the macroBS_THREAD_POOL_IMPORT_STD
is defined during compilation, on supported compilers and platforms. - The new test
check_copy()
checks that the callable object does not get copied when parallelized into multiple tasks. It will succeed on previous versions of the library, but not if perfect forwarding is removed. - The new test
check_shared_ptr()
checks that captured shared pointers do not prematurely destruct. It will fail on previous versions. - The new test
check_task_destruct()
checks that a task is destructed immediately after it executes, and therefore does not artificially extend the lifetime of any captured objects. - The new test
check_common_index_type()
checks that the type traitBS::common_index_type
(see above) works as expected. - The new tests
check_os_process_priorities()
,check_os_thread_priorities()
,check_os_process_affinity()
,check_os_thread_affinity()
, andcheck_os_thread_names()
check the corresponding features of the native extensions. - The new test
check_callables()
checks that different callable types are accepted by the thread pool. - New command line argument:
stdout
, to print to the standard output, enabled by default. - If the file
default_args.txt
exists in the same folder, the test program reads the default arguments from it (space separated in a single line). Command line arguments can still override these defaults. This is useful when debugging. - The test program will now detect and log the OS, compiler, standard library, C++ standard, available C++ features, whether the thread pool was imported as a C++20 module, and whether the standard library was imported as a module.
- The test program
- Benchmarks:
- Added new and improved benchmarks using a highly-optimized multithreaded algorithm which generates a plot of the Mandelbrot set, utilizing a normalized iteration count algorithm and linear interpolation to create smooth coloring.
- These benchmarks are heavily CPU-intensive, and much less limited by memory and cache compared to the benchmarks in previous versions (which used vector or matrix operations). This results in a much higher speedup factor due to multithreading, utilizing every core and thread to their fullest extent. This makes these benchmarks more useful for optimizing the library, since they are more sensitive to the thread pool's own performance.
- The full benchmarks are enabled using the command line argument
benchmarks
, which is enabled by default. The command line argumentplot
can be used to just plot the Mandelbrot set once, either instead of or in addition to doing the full benchmarks. This will plot the largest possible image that can be plotted in 5 seconds, and only measure the performance in pixels/ms for the entire plot. - If you want to see the actual plot, pass the
save
command line argument. The plot is saved to a BMP file, since I didn't want to depend on any 3rd-party libraries. This is off by default, since that file can get quite large.
- Development:
- A Python script
compile_cpp.py
has been added to the repository, in thescripts
folder. It can be used to compile any C++ source file with different compilers on different platforms. The compilation parameters can be configured using command line arguments and/or via an optional YAML configuration filecompile_cpp.yaml
which specifies defined macros, extra compiler flags (per compiler), include folders, modules, and the output folder. - I wrote this script to make it easier for me to test the library with different combinations of compilers, standards, and platforms using the built-in Visual Studio Code tasks. I also included three
.vscode
folders (one for each OS) in the repository, with appropriatec_cpp_properties.json
,launch.json
, andtasks.json
files that utilize this script, in case you want to use it in your own projects. However, note that this script is not meant to replace CMake or any full-fledged build system, it's just a convenient script for developing single-header libraries like this one or other small projects. - The
compile_cpp.py
script also transparently handles C++20 modules and importing the C++ Standard Library as a module in C++23. Therefore, users of this library who wish to import it as a C+20 module may find this script particularly useful. - Another Python script
test_all.py
in thescripts
folder replaces the old PowerShell test script. Tests are now performed in C++17, C++20, and C++23 modes, using all compilers available in the system (Clang, GCC, and/or MSVC). Since there are so many tests, the test script now no longer performs the benchmarks, as that would take too long. - A final Python script
clear_folder.py
in thescripts
folder is used to clean up output and temporary folders, and integrates with VS Code tasks.
- A Python script
Notes
Files
bshoshany/thread-pool-v5.0.0.zip
Files
(163.8 kB)
Name | Size | Download all |
---|---|---|
md5:8a6bda437f0f642267eb8d405056d989
|
163.8 kB | Preview Download |
Additional details
Related works
- Is supplement to
- Software: https://github.com/bshoshany/thread-pool/tree/v5.0.0 (URL)
Software
- Repository URL
- https://github.com/bshoshany/thread-pool