diff --git a/.clang-format b/.clang-format index 97d2458..1ac2b7b 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,3 @@ ---- AccessModifierOffset: -4 AlignAfterOpenBracket: DontAlign AlignArrayOfStructures: None @@ -7,12 +6,12 @@ AlignConsecutiveBitFields: None AlignConsecutiveDeclarations: None AlignConsecutiveMacros: None AlignConsecutiveShortCaseStatements: - Enabled: false + Enabled: false AlignEscapedNewlines: Left AlignOperands: DontAlign AlignTrailingComments: - Kind: Always - OverEmptyLines: 1 + Kind: Always + OverEmptyLines: 2 AllowAllArgumentsOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowBreakBeforeNoexceptSpecifier: Never @@ -26,29 +25,29 @@ AllowShortLambdasOnASingleLine: Empty AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: "Yes" +AlwaysBreakTemplateDeclarations: Yes AttributeMacros: [] BinPackArguments: true BinPackParameters: true BitFieldColonSpacing: Both BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: Always - AfterEnum: true - AfterExternBlock: true - AfterFunction: true - AfterNamespace: false - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true - BeforeLambdaBody: true - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyNamespace: true - SplitEmptyRecord: true + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterExternBlock: true + AfterFunction: true + AfterNamespace: false + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyNamespace: true + SplitEmptyRecord: true BracedInitializerIndentWidth: 4 BreakAdjacentStringLiterals: false BreakAfterAttributes: Never @@ -75,13 +74,13 @@ EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true IncludeBlocks: Preserve -IncludeIsMainSourceRegex: "" +IncludeIsMainSourceRegex: '' IndentAccessModifiers: false IndentCaseBlocks: false IndentCaseLabels: false IndentExternBlock: AfterExternBlock IndentGotoLabels: true -IndentPPDirectives: None +IndentPPDirectives: BeforeHash IndentRequires: false IndentWidth: 4 IndentWrappedFunctionNames: false @@ -90,8 +89,8 @@ JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true LambdaBodyIndentation: Signature Language: Cpp -MacroBlockBegin: "" -MacroBlockEnd: "" +MacroBlockBegin: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: Inner ObjCBinPackProtocolList: Auto @@ -132,13 +131,13 @@ SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeParensOptions: - AfterControlStatements: true - AfterForeachMacros: true - AfterFunctionDeclarationName: false - AfterFunctionDefinitionName: false - AfterIfMacros: true - AfterOverloadedOperator: false - BeforeNonEmptyParentheses: false + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDeclarationName: false + AfterFunctionDefinitionName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: false @@ -149,8 +148,8 @@ SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: false SpacesInContainerLiterals: true SpacesInLineCommentPrefix: - Maximum: 1 - Minimum: 1 + Maximum: 1 + Minimum: 1 SpacesInParentheses: false SpacesInSquareBrackets: false Standard: c++17 diff --git a/CHANGELOG.md b/CHANGELOG.md index 76b1893..1ce9116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Website: \ GitHub: * [Version history](#version-history) + * [v4.1.0 (2024-03-22)](#v410-2024-03-22) * [v4.0.1 (2023-12-28)](#v401-2023-12-28) * [v4.0.0 (2023-12-27)](#v400-2023-12-27) * [v3.5.0 (2023-05-25)](#v350-2023-05-25) @@ -28,10 +29,23 @@ GitHub: ## Version history +### v4.1.0 (2024-03-22) + +* This library is now published in [SoftwareX](https://www.sciencedirect.com/journal/softwarex)! If you use it in published research, please cite it as follows: Barak Shoshany, *"A C++17 Thread Pool for High-Performance Scientific Computing"*, [doi:10.1016/j.softx.2024.101687](https://doi.org/10.1016/j.softx.2024.101687), [SoftwareX 26 (2024) 101687](https://www.sciencedirect.com/science/article/pii/S235271102400058X), [arXiv:2105.00613](https://arxiv.org/abs/2105.00613) + * Updated the source files, as well as `README.md`, `CITATION.bib`, and `CITATION.cff` with the new citation. +* A new macro, `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING`, allows the user to disable exception handling in `submit_task()` if it is not needed, or if exceptions are explicitly disabled in the codebase. See [#139](https://github.com/bshoshany/thread-pool/issues/139). + * Note that this macro can be defined independently of `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK`. Disabling exception handling removes the `try`-`catch` block from `submit_task()`, while enabling wait deadlock checks adds a `throw` expression to `wait()`, `wait_for()`, and `wait_until()`. + * If the feature-test macro `__cpp_exceptions` is undefined, `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING` is automatically defined, and `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK` is automatically undefined. +* Replaced `#pragma once` with old-school include guards using the macros `BS_THREAD_POOL_HPP` and `BS_THREAD_POOL_UTILS_HPP`. There are two main reasons for this: + 1. Even though `#pragma once` is supported by the vast majority of modern compilers, it is still a non-standard feature, so using it technically made the library not standards compliant. + 2. Include guards make it possible to include the library twice in the same project (for example, once with priority enabled and once without) by undefining the include guard and putting the second include in its own namespace. +* Included a description of the destructor behavior for the `BS::thread_pool` class in `README.md`, in the library reference section. See [#143](https://github.com/bshoshany/thread-pool/issues/143). +* Removed unnecessary locking in `reset()` if pausing is not enabled. + ### v4.0.1 (2023-12-28) -* Fixed linkage issue caused by the global variables `BS::this_thread::get_index` and `BS::this_thread::get_pool` not being defined as `inline`. See [134](https://github.com/bshoshany/thread-pool/issues/134) and [137](https://github.com/bshoshany/thread-pool/issues/137). -* Fixed redundant cast in the `BS::thread_pool::blocks` class, and added `-Wuseless-cast` to the GCC warning flags in `BS_thread_pool_test.ps1` to catch similar issues in the future. See [133](https://github.com/bshoshany/thread-pool/pull/133). +* Fixed linkage issue caused by the global variables `BS::this_thread::get_index` and `BS::this_thread::get_pool` not being defined as `inline`. See [#134](https://github.com/bshoshany/thread-pool/issues/134) and [137](https://github.com/bshoshany/thread-pool/issues/137). +* Fixed redundant cast in the `BS::thread_pool::blocks` class, and added `-Wuseless-cast` to the GCC warning flags in `BS_thread_pool_test.ps1` to catch similar issues in the future. See [#133](https://github.com/bshoshany/thread-pool/pull/133). * Each of the three files `BS_thread_pool_test.cpp`, `BS_thread_pool.hpp`, and `BS_thread_pool_utils.hpp` now contains three macros indicating the major, minor, and patch version of the file. In addition, `BS_thread_pool_test.cpp` now checks whether the versions of all three files match, and aborts compilation if they do not. ### v4.0.0 (2023-12-27) diff --git a/CITATION.bib b/CITATION.bib index 51406fd..bbba157 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -1,13 +1,12 @@ -@article{Shoshany2021_ThreadPool, +@article{Shoshany2024_ThreadPool, archiveprefix = {arXiv}, author = {Barak Shoshany}, - doi = {10.5281/zenodo.4742687}, - eid = {arXiv:2105.00613}, + doi = {10.1016/j.softx.2024.101687}, eprint = {2105.00613}, - journal = {arXiv e-prints}, - keywords = {Computer Science - Distributed, Parallel, and Cluster Computing, D.1.3, D.1.5}, - month = {May}, - primaryclass = {cs.DC}, + journal = {SoftwareX}, + pages = {101687}, title = {{A C++17 Thread Pool for High-Performance Scientific Computing}}, - year = {2021} + url = {https://www.sciencedirect.com/science/article/pii/S235271102400058X}, + volume = {26}, + year = {2024} } diff --git a/CITATION.cff b/CITATION.cff index b64f76f..5898faf 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,26 +1,22 @@ ---- -authors: - - - family-names: Shoshany - given-names: Barak - orcid: https://orcid.org/0000-0003-2222-127X cff-version: 1.2.0 -date-released: "2021-05-03" -doi: 10.5281/zenodo.4742687 -license: MIT message: If you use this library in published research, please cite it as follows. -preferred-citation: - authors: - - - family-names: Shoshany - given-names: Barak - orcid: https://orcid.org/0000-0003-2222-127X - doi: 10.5281/zenodo.4742687 - journal: arXiv - month: 5 - title: A C++17 Thread Pool for High-Performance Scientific Computing - type: article - url: https://arxiv.org/abs/2105.00613 - year: 2021 -repository-code: https://github.com/bshoshany/thread-pool +authors: + - given-names: Barak + family-names: Shoshany + orcid: https://orcid.org/0000-0003-2222-127X + email: bshoshany@brocku.ca title: A C++17 Thread Pool for High-Performance Scientific Computing +doi: 10.1016/j.softx.2024.101687 +url: https://github.com/bshoshany/thread-pool +preferred-citation: + type: article + authors: + - given-names: Barak + family-names: Shoshany + title: A C++17 Thread Pool for High-Performance Scientific Computing + journal: SoftwareX + volume: 26 + year: 2024 + start: 101687 + doi: 10.1016/j.softx.2024.101687 + url: https://www.sciencedirect.com/science/article/pii/S235271102400058X diff --git a/LICENSE.txt b/LICENSE.txt index 365146c..5a7c645 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Barak Shoshany +Copyright (c) 2024 Barak Shoshany Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0f03838..859de63 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,15 @@ -[![Static Badge](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.4742687-b31b1b) -](https://doi.org/10.5281/zenodo.4742687) -[![arXiv:2105.00613](https://img.shields.io/badge/arXiv-2105.00613-b31b1b) -](https://arxiv.org/abs/2105.00613) +[![Author: Barak Shoshany](https://img.shields.io/badge/author-Barak_Shoshany-009933)](https://baraksh.com/) +[![DOI: 10.1016/j.softx.2024.101687](https://img.shields.io/badge/DOI-10.1016%2Fj.softx.2024.101687-b31b1b)](https://doi.org/10.1016/j.softx.2024.101687) +[![arXiv:2105.00613](https://img.shields.io/badge/arXiv-2105.00613-b31b1b)](https://arxiv.org/abs/2105.00613) [![License: MIT](https://img.shields.io/github/license/bshoshany/thread-pool)](https://github.com/bshoshany/thread-pool/blob/master/LICENSE.txt) -[![Language: C++17](https://img.shields.io/badge/Language-C%2B%2B17-yellow)](https://cppreference.com) -[![GitHub release](https://img.shields.io/github/v/release/bshoshany/thread-pool)](https://github.com/bshoshany/thread-pool/releases) -[![Vcpkg Version](https://img.shields.io/vcpkg/v/bshoshany-thread-pool)](https://vcpkg.io/) -[![Conan Version](https://img.shields.io/conan/v/bshoshany-thread-pool)](https://conan.io/center/recipes/bshoshany-thread-pool) -[![GitHub Repo stars](https://img.shields.io/github/stars/bshoshany/thread-pool?color=009999)](https://github.com/bshoshany/thread-pool/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/bshoshany/thread-pool?color=009999)](https://github.com/bshoshany/thread-pool/forks) +[![Language: C++17](https://img.shields.io/badge/Language-C%2B%2B17-yellow)](https://cppreference.com/) +[![GitHub stars](https://img.shields.io/github/stars/bshoshany/thread-pool?style=flat&color=009999)](https://github.com/bshoshany/thread-pool/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/bshoshany/thread-pool?style=flat&color=009999)](https://github.com/bshoshany/thread-pool/forks) +[![GitHub release](https://img.shields.io/github/v/release/bshoshany/thread-pool?color=660099)](https://github.com/bshoshany/thread-pool/releases) +[![Vcpkg version](https://img.shields.io/vcpkg/v/bshoshany-thread-pool?color=6600ff)](https://vcpkg.io/) +[![Meson WrapDB](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmesonbuild%2Fwrapdb%2Fmaster%2Freleases.json&query=%24%5B%22bshoshany-thread-pool%22%5D.versions%5B0%5D&label=wrapdb&color=6600ff)](https://mesonbuild.com/Wrapdb-projects.html) +[![Conan version](https://img.shields.io/conan/v/bshoshany-thread-pool?color=6600ff)](https://conan.io/center/recipes/bshoshany-thread-pool) [![Open in Visual Studio Code](https://img.shields.io/badge/Open_in_Visual_Studio_Code-007acc)](https://vscode.dev/github/bshoshany/thread-pool) -[![Barak Shoshany's Website](https://img.shields.io/badge/Barak_Shoshany's_Website-009933)](https://baraksh.com/) # `BS::thread_pool`: a fast, lightweight, and easy-to-use C++17 thread pool library @@ -19,7 +18,7 @@ Email: \ Website: \ GitHub: -This is the complete documentation for v4.0.1 of the library, released on 2023-12-28. +This is the complete documentation for v4.1.0 of the library, released on 2024-03-22. * [Introduction](#introduction) * [Motivation](#motivation) @@ -233,7 +232,7 @@ std::cout << "Thread pool library version is " << BS_THREAD_POOL_VERSION_MAJOR < Sample output: ```none -Thread pool library version is 4.0.1. +Thread pool library version is 4.1.0. ``` This can be used, for example, to allow the same code base to work with several incompatible versions of the library using `#if` directives. @@ -1067,7 +1066,7 @@ Note, however, that `BS::synced_stream::endl` should only be used if flushing is If you are using a thread pool, then your code is most likely performance-critical. Achieving maximum performance requires performing a considerable amount of benchmarking to determine the optimal settings and algorithms. Therefore, it is important to be able to measure the execution time of various computations and operations under different conditions. -The helper class `BS::timer` provides a simple way to measure execution time. It is very straightforward to use: +The utility class `BS::timer` provides a simple way to measure execution time. It is very straightforward to use: 1. Create a new `BS::timer` object. 2. Immediately before you execute the computation that you want to time, call the `start()` member function. @@ -1283,6 +1282,8 @@ int main() When using `BS::multi_future` to handle multiple futures at once, exception handling works the same way: if any of the futures may throw exceptions, you may catch these exceptions when calling `get()`, even in the case of `BS::multi_future`. +If you do not require exception handling, or if exceptions are explicitly disabled in your codebase, you can define the macro `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING` before including `BS_thread_pool.hpp`, which will disable exception handling in `submit_task()`. Note that if the feature-test macro `__cpp_exceptions` is undefined, `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING` will be automatically defined. + ### Getting information about the threads `BS::thread_pool` comes with a variety of methods to obtain information about the threads in the pool: @@ -1597,6 +1598,8 @@ int main() This time, `wait()` will detect the deadlock, and will throw an exception, causing the output to be `"Error: Deadlock!"`. +Note that if the feature-test macro `__cpp_exceptions` is undefined, `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK` will be automatically undefined. + ### Accessing native thread handles The `BS::thread_pool` member function `get_native_handles()` returns a vector containing the underlying implementation-defined thread handles for each of the pool's threads. These can then be used in an implementation-specific way to manage the threads at the OS level @@ -1783,7 +1786,7 @@ If you are using the [Conan](https://conan.io/) C/C++ package manager, you can e ```ini [requires] -bshoshany-thread-pool/4.0.1 +bshoshany-thread-pool/4.1.0 ``` To update the package to the latest version, simply change the version number. Please refer to [this package's page on ConanCenter](https://conan.io/center/recipes/bshoshany-thread-pool) for more information. @@ -1810,12 +1813,12 @@ If you are using [CMake](https://cmake.org/), you can install `BS::thread_pool` CPMAddPackage( NAME BS_thread_pool GITHUB_REPOSITORY bshoshany/thread-pool - VERSION 4.0.1) + VERSION 4.1.0) add_library(BS_thread_pool INTERFACE) target_include_directories(BS_thread_pool INTERFACE ${BS_thread_pool_SOURCE_DIR}/include) ``` -This will automatically download the indicated version of the package from this GitHub repository and include it in your project. +This will automatically download the indicated version of the package from the GitHub repository and include it in your project. It is also possible to use CPM without installing it first, by adding the following lines to `CMakeLists.txt` before `CPMAddPackage`: @@ -1845,7 +1848,7 @@ include(${CPM_DOWNLOAD_LOCATION}) CPMAddPackage( NAME BS_thread_pool GITHUB_REPOSITORY bshoshany/thread-pool - VERSION 4.0.1) + VERSION 4.1.0) add_library(BS_thread_pool INTERFACE) target_include_directories(BS_thread_pool INTERFACE ${BS_thread_pool_SOURCE_DIR}/include) add_executable(my_project main.cpp) @@ -1904,6 +1907,8 @@ The class `BS::thread_pool` is the main thread pool class. It can be used to cre * `bool wait_for(std::chrono::duration& duration)`: Wait for tasks to be completed, but stop waiting after the specified duration has passed. Returns `true` if all tasks finished running, `false` if the duration expired but some tasks are still running. * `bool wait_until(std::chrono::time_point& timeout_time)`: Wait for tasks to be completed, but stop waiting after the specified time point has been reached. Returns `true` if all tasks finished running, `false` if the time point was reached but some tasks are still running. +When a `BS::thread_pool` object goes out of scope, the destructor first waits for all tasks to complete, then destroys all threads. Note that if the pool is paused, then any tasks still in the queue will never be executed. + #### Optional features for the `BS::thread_pool` class The thread pool has several optional features that must be explicitly enabled using macros. @@ -1920,6 +1925,10 @@ The thread pool has several optional features that must be explicitly enabled us * `std::vector get_native_handles()`: Get a vector containing the underlying implementation-defined thread handles for each of the pool's threads. * **Wait deadlock checks:** Enabled by defining the macro `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK`. * When enabled, `wait()`, `wait_for()`, and `wait_until()` will check whether the user tried to call them from within a thread of the same pool, which would result in a deadlock. If so, they will throw the exception `BS::thread_pool::wait_deadlock` instead of waiting. +* **Disabling exception handling**: Achieved by defining the macro `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING`. + * This can be used to disable exception handling in `submit_task()` if it is not needed, or if exceptions are explicitly disabled in the codebase. + * Note that this macro can be defined independently of `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK`. Disabling exception handling removes the `try`-`catch` block from `submit_task()`, while enabling wait deadlock checks adds a `throw` expression to `wait()`, `wait_for()`, and `wait_until()`. + * If the feature-test macro `__cpp_exceptions` is undefined, `BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING` is automatically defined, and `BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK` is automatically undefined. #### The `BS::this_thread` namespace @@ -1993,33 +2002,32 @@ If you found this project useful, please consider [starring it on GitHub](https: ### Copyright and citing -Copyright (c) 2023 [Barak Shoshany](http://baraksh.com). Licensed under the [MIT license](LICENSE.txt). +Copyright (c) 2024 [Barak Shoshany](https://baraksh.com). Licensed under the [MIT license](LICENSE.txt). If you use this C++ thread pool library in software of any kind, please provide a link to [the GitHub repository](https://github.com/bshoshany/thread-pool) in the source code and documentation. If you use this library in published research, please cite it as follows: -* Barak Shoshany, *"A C++17 Thread Pool for High-Performance Scientific Computing"*, [doi:10.5281/zenodo.4742687](https://doi.org/10.5281/zenodo.4742687), [arXiv:2105.00613](https://arxiv.org/abs/2105.00613) (May 2021) +* Barak Shoshany, *"A C++17 Thread Pool for High-Performance Scientific Computing"*, [doi:10.1016/j.softx.2024.101687](https://doi.org/10.1016/j.softx.2024.101687), [SoftwareX 26 (2024) 101687](https://www.sciencedirect.com/science/article/pii/S235271102400058X), [arXiv:2105.00613](https://arxiv.org/abs/2105.00613) You can use the following BibTeX entry: -```none -@article{Shoshany2021_ThreadPool, +```bibtex +@article{Shoshany2024_ThreadPool, archiveprefix = {arXiv}, author = {Barak Shoshany}, - doi = {10.5281/zenodo.4742687}, - eid = {arXiv:2105.00613}, + doi = {10.1016/j.softx.2024.101687}, eprint = {2105.00613}, - journal = {arXiv e-prints}, - keywords = {Computer Science - Distributed, Parallel, and Cluster Computing, D.1.3, D.1.5}, - month = {May}, - primaryclass = {cs.DC}, + journal = {SoftwareX}, + pages = {101687}, title = {{A C++17 Thread Pool for High-Performance Scientific Computing}}, - year = {2021} + url = {https://www.sciencedirect.com/science/article/pii/S235271102400058X}, + volume = {26}, + year = {2024} } ``` -Please note that the [companion paper on arXiv](https://arxiv.org/abs/2105.00613) is updated infrequently. The paper is intended to facilitate discovery of the library by scientists who may find it useful for scientific computing purposes and to allow citing the library in scientific research, but most users should read the `README.md` file on [the GitHub repository](https://github.com/bshoshany/thread-pool) instead, as it is guaranteed to always be up to date. +Please note that the papers on [SoftwareX](https://www.sciencedirect.com/science/article/pii/S235271102400058X) and [arXiv](https://arxiv.org/abs/2105.00613) are not up to date with the latest version of the library. These publications are only intended to facilitate discovery of this library by scientists, and to enable citing it in scientific research. Documentation for the latest version is provided only by the `README.md` file in [the GitHub repository](https://github.com/bshoshany/thread-pool). ### Learning more about C++ diff --git a/include/BS_thread_pool.hpp b/include/BS_thread_pool.hpp index 2910d6f..984fc36 100644 --- a/include/BS_thread_pool.hpp +++ b/include/BS_thread_pool.hpp @@ -1,29 +1,40 @@ -#pragma once - +#ifndef BS_THREAD_POOL_HPP +#define BS_THREAD_POOL_HPP /** * @file BS_thread_pool.hpp - * @author Barak Shoshany (baraksh@gmail.com) (http://baraksh.com) - * @version 4.0.1 - * @date 2023-12-28 - * @copyright Copyright (c) 2023 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.5281/zenodo.4742687, arXiv:2105.00613 (May 2021) + * @author Barak Shoshany (baraksh@gmail.com) (https://baraksh.com) + * @version 4.1.0 + * @date 2024-03-22 + * @copyright Copyright (c) 2024 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.1016/j.softx.2024.101687, SoftwareX 26 (2024) 101687, arXiv:2105.00613 * * @brief BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library. This header file contains the main thread pool class and some additional classes and definitions. No other files are needed in order to use the thread pool itself. */ +#ifndef __cpp_exceptions + #define BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING + #undef BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK +#endif + #include // std::chrono #include // std::condition_variable #include // std::size_t -#include // std::int_least16_t -#include // std::current_exception +#ifdef BS_THREAD_POOL_ENABLE_PRIORITY + #include // std::int_least16_t +#endif +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING + #include // std::current_exception +#endif #include // std::function #include // std::future, std::future_status, std::promise #include // std::make_shared, std::make_unique, std::shared_ptr, std::unique_ptr #include // std::mutex, std::scoped_lock, std::unique_lock #include // std::nullopt, std::optional -#include // std::priority_queue, std::queue -#include // std::runtime_error +#include // std::priority_queue (if priority enabled), std::queue +#ifdef BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK + #include // std::runtime_error +#endif #include // std::thread -#include // std::conditional_t, std::decay_t, std::invoke_result_t, std::is_void_v, std::remove_const_t +#include // std::conditional_t, std::decay_t, std::invoke_result_t, std::is_void_v, std::remove_const_t (if priority enabled) #include // std::forward, std::move #include // std::vector @@ -33,8 +44,8 @@ namespace BS { // Macros indicating the version of the thread pool library. #define BS_THREAD_POOL_VERSION_MAJOR 4 -#define BS_THREAD_POOL_VERSION_MINOR 0 -#define BS_THREAD_POOL_VERSION_PATCH 1 +#define BS_THREAD_POOL_VERSION_MINOR 1 +#define BS_THREAD_POOL_VERSION_PATCH 0 class thread_pool; @@ -65,12 +76,12 @@ namespace pr { constexpr priority_t lowest = -32768; } // namespace pr -// Macros used internally to enable or disable the priority arguments in the relevant functions. -#define BS_THREAD_POOL_PRIORITY_INPUT , const priority_t priority = 0 -#define BS_THREAD_POOL_PRIORITY_OUTPUT , priority + // Macros used internally to enable or disable the priority arguments in the relevant functions. + #define BS_THREAD_POOL_PRIORITY_INPUT , const priority_t priority = 0 + #define BS_THREAD_POOL_PRIORITY_OUTPUT , priority #else -#define BS_THREAD_POOL_PRIORITY_INPUT -#define BS_THREAD_POOL_PRIORITY_OUTPUT + #define BS_THREAD_POOL_PRIORITY_INPUT + #define BS_THREAD_POOL_PRIORITY_OUTPUT #endif /** @@ -564,19 +575,19 @@ class [[nodiscard]] thread_pool */ void reset(const concurrency_t num_threads, const std::function& init_task) { - std::unique_lock tasks_lock(tasks_mutex); #ifdef BS_THREAD_POOL_ENABLE_PAUSE + std::unique_lock tasks_lock(tasks_mutex); const bool was_paused = paused; paused = true; -#endif tasks_lock.unlock(); +#endif wait(); destroy_threads(); thread_count = determine_thread_count(num_threads); threads = std::make_unique(thread_count); create_threads(init_task); - tasks_lock.lock(); #ifdef BS_THREAD_POOL_ENABLE_PAUSE + tasks_lock.lock(); paused = was_paused; #endif } @@ -597,8 +608,10 @@ class [[nodiscard]] thread_pool detach_task( [task = std::forward(task), task_promise] { +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING try { +#endif if constexpr (std::is_void_v) { task(); @@ -608,6 +621,7 @@ class [[nodiscard]] thread_pool { task_promise->set_value(task()); } +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING } catch (...) { @@ -619,6 +633,7 @@ class [[nodiscard]] thread_pool { } } +#endif } BS_THREAD_POOL_PRIORITY_OUTPUT); return task_promise->get_future(); } @@ -733,9 +748,9 @@ class [[nodiscard]] thread_pool // Macros used internally to enable or disable pausing in the waiting and worker functions. #ifdef BS_THREAD_POOL_ENABLE_PAUSE -#define BS_THREAD_POOL_PAUSED_OR_EMPTY (paused || tasks.empty()) + #define BS_THREAD_POOL_PAUSED_OR_EMPTY (paused || tasks.empty()) #else -#define BS_THREAD_POOL_PAUSED_OR_EMPTY tasks.empty() + #define BS_THREAD_POOL_PAUSED_OR_EMPTY tasks.empty() #endif /** @@ -1138,3 +1153,4 @@ class [[nodiscard]] thread_pool bool workers_running = false; }; // class thread_pool } // namespace BS +#endif diff --git a/include/BS_thread_pool_utils.hpp b/include/BS_thread_pool_utils.hpp index 86793d6..aac6706 100644 --- a/include/BS_thread_pool_utils.hpp +++ b/include/BS_thread_pool_utils.hpp @@ -1,16 +1,15 @@ -#pragma once - +#ifndef BS_THREAD_POOL_UTILS_HPP +#define BS_THREAD_POOL_UTILS_HPP /** * @file BS_thread_pool_utils.hpp - * @author Barak Shoshany (baraksh@gmail.com) (http://baraksh.com) - * @version 4.0.1 - * @date 2023-12-28 - * @copyright Copyright (c) 2023 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.5281/zenodo.4742687, arXiv:2105.00613 (May 2021) + * @author Barak Shoshany (baraksh@gmail.com) (https://baraksh.com) + * @version 4.1.0 + * @date 2024-03-22 + * @copyright Copyright (c) 2024 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.1016/j.softx.2024.101687, SoftwareX 26 (2024) 101687, arXiv:2105.00613 * * @brief BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library. This header file contains independent utility classes that are part of the library, but are not needed to use the thread pool itself. */ -#include // std::atomic #include // std::chrono #include // std::promise, std::shared_future #include // std::initializer_list @@ -26,8 +25,8 @@ namespace BS { // Macros indicating the version of the thread pool utilities library. #define BS_THREAD_POOL_UTILS_VERSION_MAJOR 4 -#define BS_THREAD_POOL_UTILS_VERSION_MINOR 0 -#define BS_THREAD_POOL_UTILS_VERSION_PATCH 1 +#define BS_THREAD_POOL_UTILS_VERSION_MINOR 1 +#define BS_THREAD_POOL_UTILS_VERSION_PATCH 0 /** * @brief A utility class to allow simple signalling between threads. @@ -201,3 +200,4 @@ class [[nodiscard]] timer std::chrono::duration elapsed_time = std::chrono::duration::zero(); }; // class timer } // namespace BS +#endif diff --git a/tests/BS_thread_pool_test.cpp b/tests/BS_thread_pool_test.cpp index 4e55968..fd74a81 100644 --- a/tests/BS_thread_pool_test.cpp +++ b/tests/BS_thread_pool_test.cpp @@ -1,9 +1,9 @@ /** * @file BS_thread_pool_test.cpp - * @author Barak Shoshany (baraksh@gmail.com) (http://baraksh.com) - * @version 4.0.1 - * @date 2023-12-28 - * @copyright Copyright (c) 2023 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.5281/zenodo.4742687, arXiv:2105.00613 (May 2021) + * @author Barak Shoshany (baraksh@gmail.com) (https://baraksh.com) + * @version 4.1.0 + * @date 2024-03-22 + * @copyright Copyright (c) 2024 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.1016/j.softx.2024.101687, SoftwareX 26 (2024) 101687, arXiv:2105.00613 * * @brief BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library. This program tests all aspects of the library, but is not needed in order to use the library. */ @@ -25,7 +25,6 @@ #include // std::mutex, std::scoped_lock #include // std::mt19937_64, std::random_device, std::uniform_int_distribution #include // std::ostringstream -#include // std::runtime_error #include // std::string, std::to_string #include // std::string_view #include // std::this_thread, std::thread @@ -33,16 +32,21 @@ #include // std::as_const, std::forward, std::move, std::pair #include // std::vector -#if defined(__APPLE__) -#include // std::terminate +// By default, the test program enables all the optional features by defining the suitable macros, so it can test them. However, if the macro `BS_THREAD_POOL_LIGHT_TEST` is defined during compilation, the optional features will not be tested, and in addition, exception handling will be disabled. +#ifndef BS_THREAD_POOL_LIGHT_TEST + #define BS_THREAD_POOL_ENABLE_NATIVE_HANDLES + #define BS_THREAD_POOL_ENABLE_PAUSE + #define BS_THREAD_POOL_ENABLE_PRIORITY + #define BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK +#else + #define BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING #endif -// By default, the test program enables all the optional features by defining the suitable macros, so it can test them. However, if the macro `BS_THREAD_POOL_LIGHT_TEST` is defined during compilation, the optional features will not be tested. -#ifndef BS_THREAD_POOL_LIGHT_TEST -#define BS_THREAD_POOL_ENABLE_NATIVE_HANDLES -#define BS_THREAD_POOL_ENABLE_PAUSE -#define BS_THREAD_POOL_ENABLE_PRIORITY -#define BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING + #include // std::runtime_error + #if defined(__APPLE__) + #include // std::terminate + #endif #endif // Include the header files for the thread pool library and its utilities. @@ -51,15 +55,15 @@ // Macros indicating the version of the thread pool test program. #define BS_THREAD_POOL_TEST_VERSION_MAJOR 4 -#define BS_THREAD_POOL_TEST_VERSION_MINOR 0 -#define BS_THREAD_POOL_TEST_VERSION_PATCH 1 +#define BS_THREAD_POOL_TEST_VERSION_MINOR 1 +#define BS_THREAD_POOL_TEST_VERSION_PATCH 0 #if (BS_THREAD_POOL_TEST_VERSION_MAJOR != BS_THREAD_POOL_VERSION_MAJOR || BS_THREAD_POOL_TEST_VERSION_MINOR != BS_THREAD_POOL_VERSION_MINOR || BS_THREAD_POOL_TEST_VERSION_PATCH != BS_THREAD_POOL_VERSION_PATCH) -#error The versions of BS_thread_pool_test.cpp and BS_thread_pool.hpp do not match. Aborting compilation. + #error The versions of BS_thread_pool_test.cpp and BS_thread_pool.hpp do not match. Aborting compilation. #endif #if (BS_THREAD_POOL_TEST_VERSION_MAJOR != BS_THREAD_POOL_UTILS_VERSION_MAJOR || BS_THREAD_POOL_TEST_VERSION_MINOR != BS_THREAD_POOL_UTILS_VERSION_MINOR || BS_THREAD_POOL_TEST_VERSION_PATCH != BS_THREAD_POOL_UTILS_VERSION_PATCH) -#error The versions of BS_thread_pool_test.cpp and BS_thread_pool_utils.hpp do not match. Aborting compilation. + #error The versions of BS_thread_pool_test.cpp and BS_thread_pool_utils.hpp do not match. Aborting compilation. #endif using int64 = std::int_fast64_t; @@ -1647,6 +1651,7 @@ void check_purge() check(no_flags_set(flags)); } +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING // ====================================== // Functions to verify exception handling // ====================================== @@ -1709,6 +1714,7 @@ void check_exceptions_multi_future() } check(caught); } +#endif // ===================================== // Functions to verify vector operations @@ -1958,7 +1964,7 @@ void check_get_pool() dual_println("Checking that all threads report the correct pool..."); std::vector> thread_pool_ptrs1(std::thread::hardware_concurrency()); std::vector> thread_pool_ptrs2(std::thread::hardware_concurrency()); - auto store_pointers = [](std::vector>& ptrs) + const std::function>&)> store_pointers = [](std::vector>& ptrs) { BS::this_thread::optional_pool ptr = BS::this_thread::get_pool(); if (ptr.has_value()) @@ -1978,7 +1984,7 @@ void check_get_pool() }); pool1.wait(); pool2.wait(); - auto check_pointers = [](const std::vector>& ptrs, const BS::thread_pool& pool) + const std::function>&, BS::thread_pool&)> check_pointers = [](const std::vector>& ptrs, const BS::thread_pool& pool) { bool correct = true; for (const std::atomic& ptr : ptrs) @@ -2257,7 +2263,7 @@ void check_performance() void show_intro() { dual_println("BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library"); - dual_println("(c) 2023 Barak Shoshany (baraksh@gmail.com) (http://baraksh.com)"); + dual_println("(c) 2024 Barak Shoshany (baraksh@gmail.com) (https://baraksh.com)"); dual_println("GitHub: https://github.com/bshoshany/thread-pool"); dual_println(); @@ -2266,24 +2272,34 @@ void show_intro() dual_println("Hardware concurrency is ", std::thread::hardware_concurrency(), '.'); dual_println(); + dual_print("Exception handling is "); +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING + dual_println("enabled."); +#else + dual_println("disabled."); +#endif + dual_print("Native handles are "); #ifdef BS_THREAD_POOL_ENABLE_NATIVE_HANDLES dual_println("enabled."); #else dual_println("disabled."); #endif + dual_print("Pausing is "); #ifdef BS_THREAD_POOL_ENABLE_PAUSE dual_println("enabled."); #else dual_println("disabled."); #endif + dual_print("Priority is "); #ifdef BS_THREAD_POOL_ENABLE_PRIORITY dual_println("enabled."); #else dual_println("disabled."); #endif + dual_print("Wait deadlock checks are "); #ifdef BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK dual_println("enabled."); @@ -2450,7 +2466,7 @@ int main(int argc, char* argv[]) #ifdef BS_THREAD_POOL_ENABLE_WAIT_DEADLOCK_CHECK check_wait_self_deadlock(); #else - print_header("NOTE: Wait deadlock checks disabled, skipping test."); + print_header("NOTE: Wait deadlock checks disabled, skipping the corresponding test."); #endif print_header("Checking detach_loop() and submit_loop():"); @@ -2469,15 +2485,19 @@ int main(int argc, char* argv[]) print_header("Checking pausing:"); check_pausing(); #else - print_header("NOTE: Pausing disabled, skipping test."); + print_header("NOTE: Pausing disabled, skipping the corresponding test."); #endif print_header("Checking purge():"); check_purge(); +#ifndef BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING print_header("Checking exception handling:"); check_exceptions_submit(); check_exceptions_multi_future(); +#else + print_header("NOTE: Exception handling disabled, skipping the corresponding test."); +#endif print_header("Checking parallelized vector operations:"); check_vectors(); @@ -2486,7 +2506,7 @@ int main(int argc, char* argv[]) print_header("Checking task priority:"); check_priority(); #else - print_header("NOTE: Task priority disabled, skipping test."); + print_header("NOTE: Task priority disabled, skipping the corresponding test."); #endif print_header("Checking thread initialization functions and get_index():"); @@ -2530,7 +2550,7 @@ int main(int argc, char* argv[]) { print_header("FAILURE: Passed " + std::to_string(tests_succeeded) + " checks, but failed " + std::to_string(tests_failed) + "!", '+'); dual_println("\nPlease submit a bug report at https://github.com/bshoshany/thread-pool/issues including the exact specifications of your system (OS, CPU, compiler, etc.) and the generated log file."); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(BS_THREAD_POOL_DISABLE_EXCEPTION_HANDLING) // macOS does not implement `std::quick_exit` for some reason. `std::exit()` cannot be used here, as it might get stuck if a deadlock occurs. std::terminate(); #else diff --git a/tests/BS_thread_pool_test.ps1 b/tests/BS_thread_pool_test.ps1 index f84c182..97ce66a 100644 --- a/tests/BS_thread_pool_test.ps1 +++ b/tests/BS_thread_pool_test.ps1 @@ -1,11 +1,15 @@ #!/usr/bin/env pwsh -# BS_thread_pool_test.ps1 -# By Barak Shoshany (baraksh@gmail.com) (http://baraksh.com) -# v4.0.1, 2023-12-28 -# Copyright (c) 2023 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.5281/zenodo.4742687, arXiv:2105.00613 (May 2021) -# -# BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library. This script compiles and runs the bundled test program with different compilers. +<# +.SYNOPSIS +BS::thread_pool: a fast, lightweight, and easy-to-use C++17 thread pool library by Barak Shoshany (baraksh@gmail.com) (https://baraksh.com) v4.1.0 (2024-03-22) +.DESCRIPTION +This script compiles and runs the bundled test program with different compilers. +.NOTES +Copyright (c) 2024 Barak Shoshany. Licensed under the MIT license. If you found this project useful, please consider starring it on GitHub! If you use this library in software of any kind, please provide a link to the GitHub repository https://github.com/bshoshany/thread-pool in the source code and documentation. If you use this library in published research, please cite it as follows: Barak Shoshany, "A C++17 Thread Pool for High-Performance Scientific Computing", doi:10.1016/j.softx.2024.101687, SoftwareX 26 (2024) 101687, arXiv:2105.00613 +.LINK +https://github.com/bshoshany/thread-pool +#> Set-StrictMode -Version Latest