Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
- { os: ubuntu-24.04, compiler: GCC 15, cc: gcc-15, cxx: g++-15, cpp_standard: 20 }
- { os: ubuntu-24.04, compiler: GCC 15, cc: gcc-15, cxx: g++-15, cpp_standard: 23 }
- { os: ubuntu-24.04, compiler: GCC 15, cc: gcc-15, cxx: g++-15, cpp_standard: 26 }
- { os: ubuntu-24.04, compiler: GCC 16, cc: gcc-16, cxx: g++-16, cpp_standard: 26 }
- { os: ubuntu-24.04, compiler: Clang 16, cc: clang-16, cxx: clang++-16, cpp_standard: 17 }
- { os: ubuntu-24.04, compiler: Clang 16, cc: clang-16, cxx: clang++-16, cpp_standard: 20 }
- { os: ubuntu-24.04, compiler: Clang 18, cc: clang-18, cxx: clang++-18, cpp_standard: 17 }
Expand All @@ -47,22 +48,27 @@ jobs:
- { os: ubuntu-24.04, compiler: Clang 21, cc: clang-21, cxx: clang++-21, cpp_standard: 20 }
- { os: ubuntu-24.04, compiler: Clang 21, cc: clang-21, cxx: clang++-21, cpp_standard: 23 }
- { os: ubuntu-24.04, compiler: Clang 21, cc: clang-21, cxx: clang++-21, cpp_standard: 26 }
- { os: ubuntu-24.04, compiler: Clang 22, cc: clang-22, cxx: clang++-22, cpp_standard: 26 }

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Add toolchain PPA (GCC 15)
if: matrix.cc == 'gcc-15'
- name: Add toolchain PPA (GCC 15/16)
if: matrix.cc == 'gcc-15' || matrix.cc == 'gcc-16'
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update

- name: Add LLVM repo (Clang 21)
if: matrix.cc == 'clang-21'
- name: Add LLVM repo (Clang 21/22)
if: matrix.cc == 'clang-21' || matrix.cc == 'clang-22'
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list
if [ "${{ matrix.cc }}" = "clang-22" ]; then
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main" | sudo tee /etc/apt/sources.list.d/llvm-22.list
else
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list
fi
sudo apt-get update

- name: Install dependencies
Expand Down
68 changes: 68 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,73 @@
# Changelog

## v2.2.0

> **No intended API/ABI breaking changes.** This release extends thread-control
> coverage to library-owned background threads and expands `ThreadInfo` into a
> lightweight per-thread control handle.

### New Features

- **`ThreadInfo` now supports bound thread IDs** -- it can be default-constructed
for the current thread or explicitly constructed from a `Tid`, then used to
`set_name`, `get_name`, `set_priority`, `set_scheduling_policy`,
`set_affinity`, `get_affinity`, `get_policy`, and `get_priority`.
The existing static convenience methods remain available. (`thread_wrapper.hpp`)

- **Library-owned background threads are now configurable** -- `ScheduledThreadPoolT`
exposes `scheduler_thread_info()` and `configure_scheduler_thread(...)`, and
`ChaosController` exposes `thread_info()` and `configure_thread(...)`, so the
scheduler/control threads are no longer anonymous internal `std::thread`s.
(`scheduled_pool.hpp`, `chaos.hpp`)

### Internal Improvements

- **Dedicated background threads now use the same wrapper/control path as worker
threads** -- scheduler and chaos threads are created as `ThreadWrapper`s and
receive stable default names, keeping thread-control behavior consistent
across the library. (`scheduled_pool.hpp`, `chaos.hpp`)

- **Callable storage is now feature-gated by language/library support** --
internal task and callback paths use modern standard call wrappers when they
are available: move-only task queues can use `std::move_only_function`
(C++23+ libraries), reusable hooks/callbacks can use
`std::copyable_function` (C++26-capable libraries), and older standards keep
the `std::function` fallback. Public aliases remain source-compatible while
new templated setter/registration overloads avoid unnecessary type-erasure
constraints. (`callable.hpp`, `thread_pool.hpp`, `scheduled_pool.hpp`,
`error_handler.hpp`, `thread_registry.hpp`, `thread_pool_with_errors.hpp`,
`pthread_wrapper.hpp`)

### Performance

- **Move-only tasks are now supported on more hot paths** -- `post`/`try_post`
and scheduler one-shot dispatch can carry move-only captures directly instead
of forcing a copyable `std::function` path on newer standard libraries.
This reduces adaptation overhead for fire-and-forget workloads and enables
more modern task payloads without wrapper glue. (`thread_pool.hpp`,
`scheduled_pool.hpp`, `thread_pool_with_errors.hpp`, `pthread_wrapper.hpp`)

### Tests

- **New regression coverage for modern callable paths** -- tests now cover
move-only `post` tasks, move-only scheduled tasks, move-only
`FutureWithErrorHandler::on_error(...)` callbacks, `PoolWithErrors` with
move-only arguments, and `ThreadInfo(Tid)` invalid-target behavior.
(`thread_pool_v2_test.cpp`, `futures_test.cpp`, `thread_config_test.cpp`)

- **New callable benchmark target** -- `callable_benchmarks` compares small
capture, large capture, and move-only capture posting overhead on
`ThreadPool` and `HighPerformancePool` as a local performance validation
tool. (`benchmarks/callable_benchmarks.cpp`, `benchmarks/CMakeLists.txt`)

### CI / Infrastructure

- **Added Linux C++26 coverage for GCC 16 and Clang 22** -- the main test
workflow now installs and runs additional `ubuntu-24.04` jobs for
`gcc-16`/`g++-16` and `clang-22`/`clang++-22`, extending verification of the
modern callable and C++26 code paths without replacing the existing matrix.
(`.github/workflows/tests.yml`)

## v2.1.0

> **No API/ABI breaking changes.** All modifications are bug fixes (aligning
Expand Down
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ or with optional **shared runtime** for multi-DSO applications.
with powerful features
- **Non-owning Views**: Zero-overhead views to configure existing threads or
find by name (Linux)
- **`ThreadInfo` Handles**: Lightweight bound thread handles for the current
thread or any known `Tid`
- **Thread Naming**: Human-readable thread names for debugging
- **Priority & Scheduling**: Fine-grained control over thread priorities and
scheduling policies
Expand All @@ -38,6 +40,9 @@ or with optional **shared runtime** for multi-DSO applications.
box - no boilerplate promise types needed
- **High-Performance Pools**: Work-stealing pool, `post()` / `try_post()`, and
optional `LightweightPool` for fire-and-forget workloads with minimal overhead
- **Modern Callable Paths**: Newer standard libraries can use
`std::move_only_function` / `std::copyable_function` internally for lower
adaptation overhead while keeping the public API source-compatible
- **Scheduled Tasks**: Run tasks at specific times, after delays, or
periodically
- **Error Handling**: Comprehensive exception handling with error callbacks and
Expand All @@ -46,6 +51,21 @@ or with optional **shared runtime** for multi-DSO applications.
- **RAII & Exception Safety**: Automatic resource management
- **Multiple Integration Methods**: CMake, CPM, Conan, FetchContent

## What's new in v2.2

Version 2.2 focuses on **broader thread-control coverage**, **more modern
callable handling on newer standards**, and **wider C++26 CI coverage**.
Highlights:

| Area | What changed |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`ThreadInfo`** | `ThreadInfo` can now bind a specific `Tid`, not just the current thread. Use it to query or configure name, priority, policy, and affinity for library-owned background threads or other known thread IDs. |
| **Background thread control**| `ScheduledThreadPoolT` exposes `scheduler_thread_info()` / `configure_scheduler_thread(...)`, and `ChaosController` exposes `thread_info()` / `configure_thread(...)`. |
| **Callable modernization** | Internal task/callback storage is feature-gated: move-only hot paths can use `std::move_only_function`, reusable hooks can use `std::copyable_function`, and older toolchains keep the `std::function` path. |
| **Move-only task support** | `post`/`try_post`, one-shot scheduled tasks, pthread entry trampolines, and error-handling wrappers now accept more move-only payloads cleanly on newer standard libraries. |
| **Tests & benchmarks** | New regression tests cover move-only tasks/callbacks and invalid `ThreadInfo(Tid)` targets. A new `callable_benchmarks` target compares small, large, and move-only task capture overhead. |
| **CI** | Linux C++26 coverage now includes `gcc-16` and `clang-22` in addition to the existing modern compiler jobs. |

## What's new in v2.0

Version 2.0 focuses on **lower-overhead submission**, **more control over
Expand Down Expand Up @@ -111,10 +131,12 @@ on:
| Ubuntu 24.04 | GCC 13 | yes | yes | yes | - |
| Ubuntu 24.04 | GCC 14 | yes | yes | yes | yes |
| Ubuntu 24.04 | GCC 15 | - | yes | yes | yes |
| Ubuntu 24.04 | GCC 16 | - | - | - | yes |
| Ubuntu 24.04 | Clang 16 | yes | yes | - | - |
| Ubuntu 24.04 | Clang 18 | yes | yes | - | - |
| Ubuntu 24.04 | Clang 19 | - | yes | yes | yes |
| Ubuntu 24.04 | Clang 21 | - | yes | yes | yes |
| Ubuntu 24.04 | Clang 22 | - | - | - | yes |
| **Linux (ARM64)** | | | | | |
| Ubuntu 24.04 ARM64 | GCC 13 (system) | yes | yes | yes | - |
| Ubuntu 24.04 ARM64 | GCC 14 | - | yes | yes | yes |
Expand All @@ -138,9 +160,14 @@ are not regularly tested in CI.
>
> **GCC 15**: Installed via `ppa:ubuntu-toolchain-r/test` on Ubuntu 24.04.
>
> **GCC 16**: Installed via `ppa:ubuntu-toolchain-r/test` on Ubuntu 24.04.
>
> **Clang 21**: Installed via the official LLVM apt repository (`apt.llvm.org`)
> on Ubuntu 24.04.
>
> **Clang 22**: Installed via the official LLVM apt repository (`apt.llvm.org`)
> on Ubuntu 24.04.
>
> **Windows ARM64**: Not currently covered by GitHub-hosted runners, requires
> self-hosted runner for testing.
>
Expand Down Expand Up @@ -236,13 +263,25 @@ int main() {
auto handle = scheduler.schedule_periodic(std::chrono::seconds(5), []() {
std::cout << "Periodic task executed!" << std::endl;
});
scheduler.configure_scheduler_thread("sched_main");

// Or use high-performance pool for frequent tasks
ScheduledHighPerformancePool scheduler_hp(4);
auto handle_hp = scheduler_hp.schedule_periodic(std::chrono::milliseconds(100), []() {
std::cout << "Frequent task!" << std::endl;
});

// Bound thread handle for library-owned threads
if (auto info = scheduler.scheduler_thread_info()) {
(void)info->set_priority(ThreadPriority::normal());
}

// Move-only payloads on modern standard libraries
auto payload = std::make_unique<int>(7);
pool.post([value = std::move(payload)]() mutable {
std::cout << "Move-only payload: " << *value << std::endl;
});

// v2: ScheduledLightweightPool - same API, LightweightPool backend (post-based dispatch)

// Error handling
Expand Down Expand Up @@ -306,6 +345,25 @@ jv.request_stop();
jv.join();
```

### `ThreadInfo` for Bound Thread IDs

Use `ThreadInfo` when you already know a `Tid` and want a lightweight control
handle without wrapping ownership.

```cpp
#include <threadschedule/threadschedule.hpp>
using namespace threadschedule;

ScheduledThreadPool scheduler(2);

if (auto info = scheduler.scheduler_thread_info()) {
auto tid = info->thread_id();
ThreadInfo bound(tid);
(void)bound.set_name("scheduler_main");
auto current_name = bound.get_name();
}
```

### Global Thread Registry

Opt-in registered threads with process-wide control, without imposing overhead
Expand Down Expand Up @@ -494,7 +552,9 @@ Zero-overhead helpers to operate on existing threads without taking ownership.

All of the above support `shutdown(ShutdownPolicy)` and `shutdown_for(timeout)`
where applicable. Use **`post()`** when you do not need a `std::future` (lower
overhead than `submit()`).
overhead than `submit()`). On newer standard libraries, internal queueing and
hook/error-callback storage can transparently use standard move-only/copyable
call wrappers.

### Configuration

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.0
2.2.0
7 changes: 6 additions & 1 deletion benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_executable(threadpool_basic_benchmarks threadpool_benchmarks.cpp)
add_executable(threadpool_throughput_benchmarks throughput_benchmarks.cpp)
add_executable(threadpool_memory_benchmarks memory_benchmarks.cpp)
add_executable(threadpool_resampling_benchmarks resampling_benchmarks.cpp)
add_executable(callable_benchmarks callable_benchmarks.cpp)

# Real-world scenario benchmarks
add_executable(web_server_benchmarks web_server_benchmarks.cpp)
Expand All @@ -18,6 +19,7 @@ set(ALL_BENCHMARK_TARGETS
threadpool_throughput_benchmarks
threadpool_memory_benchmarks
threadpool_resampling_benchmarks
callable_benchmarks
web_server_benchmarks
database_benchmarks
audio_video_benchmarks
Expand Down Expand Up @@ -56,6 +58,7 @@ add_test(NAME ThreadPoolBasicBenchmarks COMMAND threadpool_basic_benchmarks --be
add_test(NAME ThreadPoolThroughputBenchmarks COMMAND threadpool_throughput_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME ThreadPoolMemoryBenchmarks COMMAND threadpool_memory_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME ThreadPoolResamplingBenchmarks COMMAND threadpool_resampling_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME CallableBenchmarks COMMAND callable_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME WebServerBenchmarks COMMAND web_server_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME DatabaseBenchmarks COMMAND database_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
add_test(NAME AudioVideoBenchmarks COMMAND audio_video_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3)
Expand All @@ -70,7 +73,9 @@ add_custom_target(run_core_benchmarks
COMMAND threadpool_throughput_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3
COMMAND echo "=== Memory Benchmarks ==="
COMMAND threadpool_memory_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3
DEPENDS threadpool_basic_benchmarks threadpool_throughput_benchmarks threadpool_memory_benchmarks
COMMAND echo "=== Callable Benchmarks ==="
COMMAND callable_benchmarks --benchmark_min_time=2s --benchmark_repetitions=3
DEPENDS threadpool_basic_benchmarks threadpool_throughput_benchmarks threadpool_memory_benchmarks callable_benchmarks
COMMENT "Running core ThreadSchedule benchmarks (explicit target, not part of normal build)"
)

Expand Down
Loading
Loading