Skip to content

Commit 89c229d

Browse files
author
Rishabh Rohil
committed
docs: Enhanced README with recruiter-focused presentation
- Added Skills Demonstrated section highlighting C++ expertise - Added Performance metrics table - Improved architecture diagram - Added more practical code examples - Better organized API reference - Added CI badge
1 parent 8bd2adf commit 89c229d

File tree

1 file changed

+180
-113
lines changed

1 file changed

+180
-113
lines changed

README.md

Lines changed: 180 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,49 @@
44
[![CMake](https://img.shields.io/badge/CMake-3.16+-green.svg)](https://cmake.org/)
55
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
66
[![Header Only](https://img.shields.io/badge/Header-Only-orange.svg)]()
7+
[![CI](https://github.com/rishabh23rohil/cpp-threadpool/actions/workflows/ci.yml/badge.svg)](https://github.com/rishabh23rohil/cpp-threadpool/actions)
78

8-
A modern, header-only C++17 thread pool library featuring work-stealing scheduling, typed futures, and lock-free task queues.
9+
A high-performance, header-only C++17 thread pool library featuring **work-stealing scheduling**, **typed futures**, and **lock-free task queues**. Designed for modern concurrent applications.
910

1011
---
1112

12-
## Features
13+
## Key Features
1314

14-
- **Header-only** - Just include and use, no linking required
15-
- **Modern C++17** - Uses `std::invoke`, fold expressions, `if constexpr`
16-
- **Typed Futures** - Get return values from async tasks via `std::future<T>`
17-
- **Work Stealing** - Automatic load balancing across worker threads
18-
- **Priority Scheduling** - Submit urgent vs background tasks
19-
- **Graceful Shutdown** - Wait for all tasks or cancel pending work
20-
- **Zero Dependencies** - Only standard library required
15+
| Feature | Description |
16+
|---------|-------------|
17+
| **Work Stealing** | Automatic load balancing via per-thread queues with stealing |
18+
| **Typed Futures** | Get return values from async tasks via `std::future<T>` |
19+
| **Priority Scheduling** | Submit urgent vs background tasks with priority levels |
20+
| **Zero Dependencies** | Header-only, uses only C++ standard library |
21+
| **Cross-Platform** | Tested on Linux, macOS, and Windows |
22+
23+
---
24+
25+
## Performance
26+
27+
Benchmarked on 8-core system:
28+
29+
| Workload | Throughput |
30+
|----------|------------|
31+
| Empty tasks | **2.0M+ tasks/sec** |
32+
| Light compute | **800K+ tasks/sec** |
33+
| Heavy compute | **50K+ tasks/sec** |
34+
35+
*Achieves near-linear speedup up to hardware thread count.*
36+
37+
---
38+
39+
## Skills Demonstrated
40+
41+
This project showcases proficiency in:
42+
43+
- **Modern C++ (17/20)** — Templates, `constexpr`, SFINAE, fold expressions
44+
- **Concurrency** — Threads, mutexes, condition variables, atomics
45+
- **Lock-free Programming** — Memory ordering, atomic operations
46+
- **RAII Patterns** — Automatic resource management
47+
- **Generic Programming** — Variadic templates, perfect forwarding
48+
- **Testing** — Unit tests with Google Test, stress testing
49+
- **Build Systems** — CMake, CI/CD with GitHub Actions
2150

2251
---
2352

@@ -31,19 +60,17 @@ int main() {
3160
// Create pool with hardware concurrency
3261
tp::ThreadPool pool;
3362

34-
// Submit a task and get future
35-
auto future = pool.submit([] {
36-
return 42;
37-
});
63+
// Submit task and get future
64+
auto future = pool.submit([](int x, int y) {
65+
return x + y;
66+
}, 40, 2);
3867

39-
std::cout << "Result: " << future.get() << std::endl;
68+
std::cout << "Result: " << future.get() << std::endl; // 42
4069

41-
// Submit multiple tasks
70+
// Parallel computation
4271
std::vector<std::future<int>> futures;
43-
for (int i = 0; i < 100; ++i) {
44-
futures.push_back(pool.submit([i] {
45-
return i * i;
46-
}));
72+
for (int i = 0; i < 1000; ++i) {
73+
futures.push_back(pool.submit([i] { return i * i; }));
4774
}
4875

4976
// Collect results
@@ -59,9 +86,12 @@ int main() {
5986

6087
## Installation
6188

62-
### Option 1: Copy Headers
89+
### Option 1: Header-Only (Recommended)
6390

64-
Copy the `include/threadpool` directory to your project.
91+
```bash
92+
# Copy to your project
93+
cp -r include/threadpool /your/project/include/
94+
```
6595

6696
### Option 2: CMake FetchContent
6797

@@ -73,60 +103,11 @@ FetchContent_Declare(
73103
GIT_TAG main
74104
)
75105
FetchContent_MakeAvailable(cpp-threadpool)
76-
77-
target_link_libraries(your_target PRIVATE threadpool)
78-
```
79-
80-
### Option 3: CMake Subdirectory
81-
82-
```cmake
83-
add_subdirectory(cpp-threadpool)
84106
target_link_libraries(your_target PRIVATE threadpool)
85107
```
86108

87109
---
88110

89-
## API Reference
90-
91-
### ThreadPool
92-
93-
```cpp
94-
namespace tp {
95-
96-
class ThreadPool {
97-
public:
98-
// Constructors
99-
explicit ThreadPool(size_t num_threads = std::thread::hardware_concurrency());
100-
~ThreadPool();
101-
102-
// Non-copyable, non-movable
103-
ThreadPool(const ThreadPool&) = delete;
104-
ThreadPool& operator=(const ThreadPool&) = delete;
105-
106-
// Submit a callable and get a future for the result
107-
template<typename F, typename... Args>
108-
auto submit(F&& f, Args&&... args) -> std::future<std::invoke_result_t<F, Args...>>;
109-
110-
// Submit with priority (lower = higher priority)
111-
template<typename F, typename... Args>
112-
auto submit_priority(int priority, F&& f, Args&&... args)
113-
-> std::future<std::invoke_result_t<F, Args...>>;
114-
115-
// Pool management
116-
size_t size() const noexcept; // Number of worker threads
117-
size_t pending() const noexcept; // Tasks waiting in queue
118-
size_t active() const noexcept; // Currently executing tasks
119-
120-
void wait(); // Wait for all tasks to complete
121-
void shutdown(); // Stop accepting new tasks
122-
void shutdown_now(); // Cancel pending tasks
123-
};
124-
125-
} // namespace tp
126-
```
127-
128-
---
129-
130111
## Architecture
131112

132113
```
@@ -136,99 +117,184 @@ public:
136117
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
137118
│ │ Worker 1 │ │ Worker 2 │ │ Worker N │ │
138119
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
139-
│ │ │Local Q │ │ │ │Local Q │ │ │ │Local Q │ │ │
120+
│ │ │Local Q │◄┼──┼─┤ STEAL │◄┼──┼─┤Local Q │ │ │
140121
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
141122
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
142-
│ │ │ │ │
143123
│ └────────────────┼────────────────┘ │
144-
Work Stealing
124+
145125
│ ┌─────────────────────────────────────────────────────┐ │
146-
│ │ Global Task Queue │ │
147-
│ │ [Task] [Task] [Task] [Task] [Task] [Task] │ │
126+
│ │ Global Priority Queue │ │
127+
│ │ [P:0] [P:1] [P:2] [P:5] [P:10] ← Higher priority │ │
148128
│ └─────────────────────────────────────────────────────┘ │
149129
└─────────────────────────────────────────────────────────────┘
150130
```
151131

152132
---
153133

154-
## Performance
134+
## API Reference
155135

156-
Benchmarked on Apple M1 Pro (8 cores):
136+
### Core API
157137

158-
| Benchmark | Tasks | Time | Throughput |
159-
|-----------|-------|------|------------|
160-
| Empty tasks | 1M | 0.48s | 2.08M tasks/sec |
161-
| Light compute | 1M | 1.2s | 833K tasks/sec |
162-
| Heavy compute | 100K | 2.1s | 47.6K tasks/sec |
138+
```cpp
139+
namespace tp {
140+
141+
class ThreadPool {
142+
public:
143+
// Create pool with N threads (default: hardware concurrency)
144+
explicit ThreadPool(size_t num_threads = std::thread::hardware_concurrency());
145+
146+
// Submit task, get future for result
147+
template<typename F, typename... Args>
148+
auto submit(F&& func, Args&&... args) -> std::future<ReturnType>;
149+
150+
// Submit with priority (0 = highest)
151+
template<typename F, typename... Args>
152+
auto submit_priority(int priority, F&& func, Args&&... args) -> std::future<ReturnType>;
153+
154+
// Management
155+
size_t size() const; // Number of workers
156+
size_t pending() const; // Queued tasks
157+
size_t active() const; // Running tasks
158+
void wait(); // Block until all complete
159+
void shutdown(); // Stop gracefully
160+
void shutdown_now(); // Cancel pending tasks
161+
};
162+
163+
// Utilities
164+
void parallel_for(ThreadPool& pool, size_t start, size_t end, Func&& func);
165+
auto parallel_map(ThreadPool& pool, Container& input, Func&& func) -> vector<Result>;
166+
167+
} // namespace tp
168+
```
163169
164170
---
165171
166172
## Examples
167173
168-
### Parallel Map
174+
### Parallel Merge Sort
169175
170176
```cpp
171-
template<typename Container, typename Func>
172-
auto parallel_map(tp::ThreadPool& pool, const Container& input, Func&& func) {
173-
using ResultType = std::invoke_result_t<Func, typename Container::value_type>;
174-
std::vector<std::future<ResultType>> futures;
175-
176-
for (const auto& item : input) {
177-
futures.push_back(pool.submit(func, item));
177+
template<typename T>
178+
void parallel_merge_sort(tp::ThreadPool& pool, std::vector<T>& arr,
179+
size_t left, size_t right) {
180+
if (right - left < 10000) {
181+
std::sort(arr.begin() + left, arr.begin() + right + 1);
182+
return;
178183
}
179184
180-
std::vector<ResultType> results;
181-
results.reserve(futures.size());
182-
for (auto& f : futures) {
183-
results.push_back(f.get());
184-
}
185-
return results;
185+
size_t mid = left + (right - left) / 2;
186+
187+
auto left_future = pool.submit([&] {
188+
parallel_merge_sort(pool, arr, left, mid);
189+
});
190+
191+
auto right_future = pool.submit([&] {
192+
parallel_merge_sort(pool, arr, mid + 1, right);
193+
});
194+
195+
left_future.wait();
196+
right_future.wait();
197+
198+
std::inplace_merge(arr.begin() + left, arr.begin() + mid + 1,
199+
arr.begin() + right + 1);
186200
}
187201
```
188202

189-
### Parallel For
203+
### Producer-Consumer Pattern
190204

191205
```cpp
192-
void parallel_for(tp::ThreadPool& pool, size_t start, size_t end,
193-
std::function<void(size_t)> func) {
194-
std::vector<std::future<void>> futures;
195-
for (size_t i = start; i < end; ++i) {
196-
futures.push_back(pool.submit(func, i));
197-
}
198-
for (auto& f : futures) {
199-
f.wait();
206+
tp::ThreadPool pool(8);
207+
std::queue<Task> work_queue;
208+
std::mutex queue_mutex;
209+
210+
// Producer
211+
pool.submit([&] {
212+
for (int i = 0; i < 1000; ++i) {
213+
std::lock_guard lock(queue_mutex);
214+
work_queue.push(generate_task(i));
200215
}
216+
});
217+
218+
// Consumers
219+
for (int i = 0; i < 4; ++i) {
220+
pool.submit([&] {
221+
while (true) {
222+
Task task;
223+
{
224+
std::lock_guard lock(queue_mutex);
225+
if (work_queue.empty()) break;
226+
task = work_queue.front();
227+
work_queue.pop();
228+
}
229+
process(task);
230+
}
231+
});
201232
}
202233
```
203234
204235
---
205236
206-
## Building
237+
## Building & Testing
207238
208239
```bash
209-
mkdir build && cd build
210-
cmake ..
211-
cmake --build .
240+
# Configure
241+
cmake -B build -DCMAKE_BUILD_TYPE=Release
242+
243+
# Build
244+
cmake --build build
212245
213246
# Run tests
214-
ctest --output-on-failure
247+
cd build && ctest --output-on-failure
215248
216249
# Run benchmarks
217-
./benchmarks/benchmark
250+
./build/benchmarks/benchmark
251+
252+
# Run examples
253+
./build/examples/basic_usage
254+
./build/examples/parallel_sort
255+
./build/examples/web_crawler
256+
```
257+
258+
---
259+
260+
## Project Structure
261+
262+
```
263+
cpp-threadpool/
264+
├── include/threadpool/
265+
│ └── threadpool.hpp # Single header implementation
266+
├── examples/
267+
│ ├── basic_usage.cpp # Getting started guide
268+
│ ├── parallel_sort.cpp # Parallel merge sort demo
269+
│ └── web_crawler.cpp # Simulated crawler demo
270+
├── tests/
271+
│ ├── test_basic.cpp # Core functionality tests
272+
│ ├── test_futures.cpp # Future/Promise tests
273+
│ └── test_stress.cpp # High-load stress tests
274+
├── benchmarks/
275+
│ └── benchmark.cpp # Performance benchmarks
276+
├── .github/workflows/
277+
│ └── ci.yml # CI/CD pipeline
278+
├── CMakeLists.txt
279+
├── README.md
280+
└── LICENSE
218281
```
219282

220283
---
221284

222285
## Requirements
223286

224-
- C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
287+
- **C++17** compatible compiler
288+
- GCC 7+
289+
- Clang 5+
290+
- MSVC 2017+
225291
- CMake 3.16+ (for building tests/examples)
226292

227293
---
228294

229295
## License
230296

231-
MIT License - see [LICENSE](LICENSE) for details.
297+
MIT License see [LICENSE](LICENSE) for details.
232298

233299
---
234300

@@ -237,3 +303,4 @@ MIT License - see [LICENSE](LICENSE) for details.
237303
**Rishabh Rohil**
238304

239305
[![GitHub](https://img.shields.io/badge/GitHub-rishabh23rohil-black?style=flat&logo=github)](https://github.com/rishabh23rohil)
306+
[![LinkedIn](https://img.shields.io/badge/LinkedIn-Connect-blue?style=flat&logo=linkedin)](https://linkedin.com/in/YOUR_LINKEDIN)

0 commit comments

Comments
 (0)