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
6 changes: 3 additions & 3 deletions .github/workflows/macos_arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:

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

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Check Clang Version
run: clang++ --version
Expand All @@ -33,4 +33,4 @@ jobs:

- name: Test
working-directory: build
run: ctest
run: ctest
6 changes: 3 additions & 3 deletions .github/workflows/macos_x86_64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:

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

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Check Clang Version
run: clang++ --version
Expand All @@ -33,4 +33,4 @@ jobs:

- name: Test
working-directory: build
run: ctest
run: ctest
6 changes: 3 additions & 3 deletions .github/workflows/ubuntu_X86_64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ jobs:

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

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libgtest-dev libbenchmark-dev cmake

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Check GCC Version
run: g++ --version
Expand All @@ -44,4 +44,4 @@ jobs:
run: ./build/benchmarkbin/ThreadPool_ThreadTask_Benchmark

- name: Run ThreadPool Benchmarks
run: ./build/benchmarkbin/ThreadPool_ThreadPool_Benchmark
run: ./build/benchmarkbin/ThreadPool_ThreadPool_Benchmark
6 changes: 3 additions & 3 deletions .github/workflows/ubuntu_arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ jobs:

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

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libgtest-dev libbenchmark-dev cmake

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Check GCC Version
run: g++ --version
Expand All @@ -35,4 +35,4 @@ jobs:

- name: Test
working-directory: build
run: ctest -LE benchmark --output-on-failure
run: ctest -LE benchmark --output-on-failure
6 changes: 3 additions & 3 deletions .github/workflows/ubuntu_riscv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ jobs:

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

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libgtest-dev libbenchmark-dev cmake

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Check GCC Version
run: g++ --version
Expand All @@ -35,4 +35,4 @@ jobs:

- name: Test
working-directory: build
run: ctest -LE benchmark --output-on-failure
run: ctest -LE benchmark --output-on-failure
6 changes: 3 additions & 3 deletions .github/workflows/windows_arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

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

- name: Install vcpkg
run: |
Expand All @@ -35,7 +35,7 @@ jobs:
vcpkg integrate install

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -80,4 +80,4 @@ jobs:

- name: Test
working-directory: build
run: ctest -LE benchmark --output-on-failure -C Release
run: ctest -LE benchmark --output-on-failure -C Release
4 changes: 2 additions & 2 deletions .github/workflows/windows_x86_64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

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

- name: Install vcpkg
run: |
Expand All @@ -37,7 +37,7 @@ jobs:
vcpkg integrate install

- name: Setup CMake and Ninja
uses: lukka/get-cmake@v3.21.1
uses: lukka/get-cmake@v4.2.0

- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ endif()
# Get the name of the folder and use it as the project name
get_filename_component(PARENT_DIR_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" PARENT_DIR_NAME ${PARENT_DIR_NAME})
project(${PARENT_DIR_NAME} VERSION 2.0.0 DESCRIPTION "A Threadpool function library" LANGUAGES CXX)
project(${PARENT_DIR_NAME} VERSION 2.1.0 DESCRIPTION "A Threadpool function library" LANGUAGES CXX)
#------------------------------------------------------------------------------------------
# Set the C++ standard
set(CMAKE_CXX_STANDARD 20)
Expand Down
41 changes: 41 additions & 0 deletions benchmark/ThreadPoolBenchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,28 @@ static void BM_ThreadPool_ExecuteTask(benchmark::State& state) {
}
BENCHMARK(BM_ThreadPool_ExecuteTask)->RangeMultiplier(2)->Range(4, 64)->Complexity(benchmark::oAuto);

// Benchmark for enqueueing void tasks (asynchronous fire-and-forget)
static void BM_ThreadPool_VoidAsync(benchmark::State& state) {
ThreadPool::ThreadPool<ThreadPool::ThreadMode::STANDARD> pool(state.range(0));
for (auto _ : state) {
pool.queue([]() {});
}
state.SetComplexityN(state.range(0));
}
BENCHMARK(BM_ThreadPool_VoidAsync)->RangeMultiplier(2)->Range(4, 64)->Complexity(benchmark::oAuto);

// Benchmark for enqueueing void tasks (synchronous with future)
static void BM_ThreadPool_VoidSync(benchmark::State& state) {
ThreadPool::ThreadPool<ThreadPool::ThreadMode::STANDARD> pool(state.range(0));
for (auto _ : state) {
auto fut = pool.queue<ThreadPool::ThreadSynchronization::SYNCHRONOUS>([]() {});
benchmark::DoNotOptimize(fut.valid());
fut.wait();
}
state.SetComplexityN(state.range(0));
}
BENCHMARK(BM_ThreadPool_VoidSync)->RangeMultiplier(2)->Range(4, 64)->Complexity(benchmark::oAuto);

// Benchmark for handling a burst of tasks
static void BM_ThreadPool_BurstTasks(benchmark::State& state) {
ThreadPool::ThreadPool<ThreadPool::ThreadMode::STANDARD> pool(state.range(0));
Expand Down Expand Up @@ -71,6 +93,25 @@ static void BM_ThreadPool_PriorityQueueTask(benchmark::State& state) {
}
BENCHMARK(BM_ThreadPool_PriorityQueueTask)->RangeMultiplier(2)->Range(4, 64)->Complexity(benchmark::oAuto);

// Benchmark for enum-to-string conversions
static void BM_ThreadMode_NameLookup(benchmark::State& state) {
const auto mode = state.range(0) == 0 ? ThreadPool::ThreadMode::STANDARD : ThreadPool::ThreadMode::PRIORITY;
for (auto _ : state) {
benchmark::DoNotOptimize(ThreadPool::ThreadMode_name(mode));
}
state.SetComplexityN(1);
}
BENCHMARK(BM_ThreadMode_NameLookup)->DenseRange(0, 1);

static void BM_ThreadSynchronization_NameLookup(benchmark::State& state) {
const auto sync_mode = state.range(0) == 0 ? ThreadPool::ThreadSynchronization::ASYNCHRONOUS : ThreadPool::ThreadSynchronization::SYNCHRONOUS;
for (auto _ : state) {
benchmark::DoNotOptimize(ThreadPool::ThreadSynchronization_name(sync_mode));
}
state.SetComplexityN(1);
}
BENCHMARK(BM_ThreadSynchronization_NameLookup)->DenseRange(0, 1);

BENCHMARK_MAIN();

/*
Expand Down
22 changes: 21 additions & 1 deletion example/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ int main(void) {
_threads.queue([](int value) { std::cout << "ThreadMode::STANDARD Print Value:[" << value << "]" << std::endl; }, i);
}
}
{
// Demonstrate synchronous void task submission with a waitable future.
ThreadPool::ThreadPool<ThreadPool::ThreadMode::STANDARD> _threads(_size);
std::atomic<int> counter{0};

std::vector<std::future<void>> futures;
futures.reserve(_size);
for (size_t i = 0; i < _size; ++i) {
auto fut = _threads.queue<ThreadPool::ThreadSynchronization::SYNCHRONOUS>([&counter]() {
counter.fetch_add(1, std::memory_order_relaxed);
});
futures.emplace_back(std::move(fut));
}

for (auto& fut : futures) {
fut.wait();
}

std::cout << "Synchronous void tasks completed. Count:" << counter.load() << std::endl;
}
{
ThreadPool::ThreadPool<ThreadPool::ThreadMode::PRIORITY> _threads(_size);
std::vector<std::future<int>> results;
Expand Down Expand Up @@ -167,4 +187,4 @@ int main(void) {

}
return 0;
}
}
49 changes: 48 additions & 1 deletion include/ThreadMode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,52 @@ namespace ThreadPool {
//--------------------------------------------------------------
}// end constexpr std::string_view to_string(ThreadMode mode)
//--------------------------------------------------------------
/**
* @enum ThreadSynchronization
* @brief Enum class to specify synchronization preference for void tasks.
*
* @details Use this to choose whether void-returning tasks should expose a future to callers.
* `ASYNCHRONOUS` keeps void tasks fire-and-forget, while `SYNCHRONOUS` exposes a future so callers can wait.
*
* @code
* // Fire-and-forget void task
* pool.queue<ThreadPool::ThreadSynchronization::ASYNCHRONOUS>([] { work });
*
* // Void task that can be waited on
* auto fut = pool.queue<ThreadPool::ThreadSynchronization::SYNCHRONOUS>([] { work });
* fut.wait();
* @endcode
*/
enum class ThreadSynchronization : bool {
ASYNCHRONOUS = false,
SYNCHRONOUS = true
}; // end enum class ThreadSynchronization
//--------------------------------------------------------------
/**
* @brief Converts the ThreadSynchronization enum to a string representation.
*
* @details This helper is useful for logging and debugging synchronization choices at runtime.
* @param mode The ThreadSynchronization enum value to convert.
*
* @return std::string_view A string representation of the ThreadSynchronization enum value.
*
* @example
* @code
* constexpr auto sync_mode = ThreadPool::ThreadSynchronization::SYNCHRONOUS;
* constexpr auto name = ThreadPool::ThreadSynchronization_name(sync_mode);
* // name == "SYNCHRONOUS"
* @endcode
*/
constexpr std::string_view ThreadSynchronization_name(const ThreadSynchronization& mode) {
switch (mode) {
case ThreadSynchronization::ASYNCHRONOUS:
return "ASYNCHRONOUS";
case ThreadSynchronization::SYNCHRONOUS:
return "SYNCHRONOUS";
default:
return "UNKNOWN";
}
}// end constexpr std::string_view ThreadSynchronization_name(const ThreadSynchronization& mode)
//--------------------------------------------------------------
} // end namespace ThreadPool
//--------------------------------------------------------------
//--------------------------------------------------------------
Loading
Loading