Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SmallThreadPool

A single-header, portable C++17 thread pool library.

Why?

I needed a small, portable thread pool that also gracefully simplified to single-threaded execution when used with 0 threads or compiled with emscripten without pthread support. Also, SmallThreadPool is small -- about 1000 lines of heavily doxygen-commented code.

Credits

The overall design is based on the article and code by Max Liani, with some ideas (for the higher-level template wrappers) taken from Wenzel Jakob's nanothread library.

Usage

Just

#include "smallthreadpool.h"

to get started.

In one translation unit (source file), you must #define SMALL_THREADPOOL_IMPLEMENTATION before including the header.

One of the core constructs is the parallel for-loop. Here's an example of how to use it:

#include <spdlog/spdlog.h>
#define SMALL_THREADPOOL_IMPLEMENTATION
#include <smallthreadpool.h>

int main(int, char **) {
    int result[100];

    // Call the provided lambda function 100 times with blocks of size 1
    stp::parallel_for(
        blocked_range<uint32_t>(0   // begin,
                                100 // end,
                                1   // block_size
                                ),

        // The callback is allowed to be a stateful lambda function
        [&](uint32_t begin, uint32_t end, int unit_index, int thread_index) {
            for (uint32_t i = begin; i != end; ++i) {
                spdlog::info("Worker thread {} is starting to process work unit {}\n",
                             pool_thread_id(), i);

                // Write to variables defined in the caller's frame
                result[i] = i;
            }
        }
    );
}

There are a number of other constructs provided by smallthreadpool, including a do_async function to perform a single computation asynchronously on the thread pool, a Barrier thread-coordination mechanism class, and a for_each_thread function to execute a function once for each thread in the thread pool. See the extensive source code doxygen comments for more usage info and examples.

Tests

The library itself needs no build system. The test suite does, so its CMake project lives under tests/ and is configured directly:

cmake -S tests -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure

Useful options:

Option Values Meaning
STP_TESTS_CXX_STANDARD 17 (default), 20 C++ standard to build the tests with
STP_TESTS_SANITIZER empty, Address;Undefined, Thread Build under the given sanitizer
STP_TESTS_WERROR ON (default), OFF Treat compiler warnings as errors

For example, to hunt for data races:

cmake -S tests -B build-tsan -DCMAKE_BUILD_TYPE=Release -DSTP_TESTS_SANITIZER=Thread
cmake --build build-tsan
TSAN_OPTIONS=halt_on_error=1 ctest --test-dir build-tsan --output-on-failure

The suite deliberately compiles the implementation into its own translation unit, separate from the tests that use the header, since some defects only appear when the pool's statics are defined in one translation unit and read from another. CI runs the whole matrix (GCC, Clang, AppleClang and MSVC; C++17 and C++20; ASan+UBSan and TSan) on every push.

About

A single-header, portable C++11 thread pool library

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages