A C++20 thread pool library implementing priority-based job scheduling with worker threads.
- Priority-based job scheduling (HIGH, NORMAL, LOW)
- Flexible worker configuration - Workers can be configured to handle specific priority jobs
- Lambda job support - Create jobs inline without inheritance using C++20 lambda functions
- Future-based async execution - Submit tasks and get results via
std::futurewith full type safety - Cross-platform support - Windows (MSVC), macOS (Clang), Linux (GCC)
- Thread-safe - Uses mutexes and condition variables for synchronization
- Smart pointer based - Modern C++ memory management with smart pointers throughout
thread_pool/
├── CMakeLists.txt # Main build configuration
├── src/ # Library source code
│ ├── job.{h,cpp} # Abstract job base class
│ ├── job_manager.{h,cpp} # Job queue management
│ ├── thread_pool.{h,cpp} # Thread pool manager
│ └── thread_worker.{h,cpp} # Worker thread implementation
└── sample/ # Sample applications
├── CMakeLists.txt # Sample build configuration
├── sample.cpp # Traditional inheritance-based jobs
├── sample_lambda.cpp # Lambda-based jobs
├── future_sample.cpp # Future-based async job submission
├── test_return_values.cpp # Return value handling
└── sample_job.h # Sample job implementation
thread_pool- Main thread pool manager with support for lambda jobs and future-based async executionthread_worker- Individual worker threads with priority affinityjob_manager- Job queue management with priority queuesjob- Abstract base class for jobs (supports both inheritance and lambda-based jobs)
- CMake 3.28 or higher
- C++20 compatible compiler:
- MSVC 2019+ (Windows)
- Clang 10+ (macOS/Linux)
- GCC 10+ (Linux)
mkdir build
cd build
cmake ..
makemkdir build
cd build
cmake ..
cmake --build . --config ReleaseThis will build:
thread_worker- Static librarysample- Sample executable demonstrating inheritance-based jobssample_lambda- Sample executable demonstrating lambda-based jobsfuture_sample- Sample executable demonstrating future-based async job submissiontest_return_values- Sample executable demonstrating return value handling
If you only want to build the library without the sample:
mkdir build
cd build
cmake ..
cmake --build . --target thread_workerAfter building, run the sample executables from the build directory:
# macOS / Linux
./build/sample/sample
# Windows
.\build\sample\Release\sample.exe# macOS / Linux
./build/sample/sample_lambda
# Windows
.\build\sample\Release\sample_lambda.exe# macOS / Linux
./build/sample/future_sample
# Windows
.\build\sample\Release\future_sample.exe# macOS / Linux
./build/sample/test_return_values
# Windows
.\build\sample\Release\test_return_values.exe#include "thread_pool.h"
#include "thread_worker.h"
int main()
{
// Create thread pool
auto pool = std::make_shared<thread_pool>();
// Add workers
auto worker = std::make_shared<thread_worker>(job_priority::NORMAL_PRIORITY);
pool->addWorker(worker);
pool->setWorkersPriorityNumbers();
// Create and add a lambda job
auto job = std::make_shared<::job>(
1, // job_id
job_priority::NORMAL_PRIORITY, // priority
[]() { // work lambda
std::cout << "Task executed!" << std::endl;
}
);
pool->addJob(job);
// Shutdown and wait for completion
pool->stopPool(true);
return 0;
}#include "thread_pool.h"
#include "thread_worker.h"
int main()
{
// Create thread pool
auto pool = std::make_shared<thread_pool>();
// Add workers
for (int i = 0; i < 2; i++)
{
auto worker = std::make_shared<thread_worker>(job_priority::NORMAL_PRIORITY);
pool->addWorker(worker);
}
pool->setWorkersPriorityNumbers();
// Submit a task and get a future
auto future = pool->submit(
job_priority::NORMAL_PRIORITY,
[](int a, int b) {
return a + b;
},
21,
21
);
// Wait for result and print
std::cout << "Result: " << future.get() << std::endl;
// Shutdown pool
pool->stopPool(true);
return 0;
}There are three ways to create and execute jobs:
Create jobs directly with lambda functions without inheritance:
auto pool = std::make_shared<thread_pool>();
auto worker = std::make_shared<thread_worker>(job_priority::NORMAL_PRIORITY);
pool->addWorker(worker);
pool->setWorkersPriorityNumbers();
// Simple lambda job
auto job = std::make_shared<::job>(
1, // job_id
job_priority::HIGH_PRIORITY, // priority
[]() { // work lambda
std::cout << "Task executed!" << std::endl;
}
);
pool->addJob(job);Lambda jobs support captures for accessing external data:
std::atomic<int> counter{0};
auto job = std::make_shared<::job>(
2,
job_priority::NORMAL_PRIORITY,
[&counter]() { // Capture counter by reference
counter++;
std::cout << "Counter: " << counter << std::endl;
}
);
pool->addJob(job);Simplified constructors are also available:
// Auto job_id = 0, default priority = NORMAL
auto simple_job = std::make_shared<::job>([]() {
std::cout << "Simple task!" << std::endl;
});
pool->addJob(simple_job);
// Specify priority only
auto priority_job = std::make_shared<::job>(
job_priority::HIGH_PRIORITY,
[]() { std::cout << "High priority task!" << std::endl; }
);
pool->addJob(priority_job);Use the submit() method to execute tasks and get results via std::future:
// Submit with priority
auto future = pool->submit(
job_priority::HIGH_PRIORITY,
[](int a, int b) {
return a * b;
},
6,
7
);
std::cout << "Result: " << future.get() << std::endl; // Output: 42
// Submit with default normal priority
auto future2 = pool->submit([]() {
return "Hello from thread pool!";
});
std::string result = future2.get();Inherit from the job base class and implement the work() method:
class my_custom_job : public job
{
public:
my_custom_job(unsigned long long job_id, job_priority priority)
: job(job_id)
{
setJobPriority(priority);
}
void work() override
{
// Your job logic here
std::cout << "Doing work..." << std::endl;
}
};
// Usage
auto job = std::make_shared<my_custom_job>(1, job_priority::HIGH_PRIORITY);
pool->addJob(job);The thread pool supports three priority levels:
- HIGH_PRIORITY - Processed first by high-priority workers, then normal workers
- NORMAL_PRIORITY - Processed by all workers
- LOW_PRIORITY - Processed last, mainly by low-priority workers
- High Priority Workers: Process HIGH → NORMAL jobs
- Normal Priority Workers: Process NORMAL → LOW → HIGH jobs
- Low Priority Workers: Process LOW → NORMAL → HIGH jobs
// Worker management
void addWorker(std::shared_ptr<thread_worker> worker);
void removeWorker(std::shared_ptr<thread_worker> worker);
void setWorkersPriorityNumbers();
int getWorkerNumbers();
// Job submission
void addJob(std::shared_ptr<job> new_job);
// Future-based async execution (returns std::future)
template <typename F, typename... Args>
auto submit(F&& func, Args&&... args) -> std::future<std::invoke_result_t<F, Args...>>;
template <typename F, typename... Args>
auto submit(job_priority priority, F&& func, Args&&... args) -> std::future<std::invoke_result_t<F, Args...>>;
// Pool control
void stopPool(bool wait_for_finish_jobs = false, std::chrono::seconds max_wait_time = std::chrono::seconds(0));thread_worker(job_priority priority = job_priority::NORMAL_PRIORITY);
void startWorker();
void stopWorker();
job_priority getPriority();void push_job(std::shared_ptr<job> new_job);
std::shared_ptr<job> pop_job(std::vector<job_priority> job_priorities);
int getAllJobCount();
int getJobCount(std::vector<job_priority> job_priorities);- ✅ Lambda job support - Full support for lambda functions as jobs without requiring inheritance
- ✅ Future-based async execution - Added
submit()method that returnsstd::futurefor getting task results - ✅ Simplified API - Removed legacy
callback_dataandjob_dataclasses for cleaner, more intuitive interface - ✅ Multiple sample applications - Comprehensive examples demonstrating different usage patterns
The following improvements are planned for future releases:
- Remove raw pointer usage - Eliminate remaining raw pointers in favor of smart pointers
- Modern C++ improvements - Continue updating codebase to fully utilize C++20 features and best practices
- Watchdog for starvation prevention - Implement watchdog mechanism to detect and prevent job starvation
- Job chain support - Implement job chaining capabilities to define dependent task sequences
- Enhanced exception handling - Improve error handling and reporting throughout the library
This project is provided as-is for educational and commercial use.