feat: Add new thread_pool component built on top of Task#673
Conversation
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Pull request overview
Adds a new thread_pool component to ESPP, providing an espp::ThreadPool API backed by espp::Task workers, plus an ESP-IDF example project demonstrating job submission and basic stats reporting.
Changes:
- Introduces
espp::ThreadPoolimplementation with a configurable worker count, optional bounded queue, and submission/statistics APIs. - Adds an ESP-IDF example (
components/thread_pool/example) showing how to run multiple jobs and wait for completion. - Adds component packaging metadata (
idf_component.yml) and CMake integration for the new component.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| components/thread_pool/src/thread_pool.cpp | Implements worker lifecycle, queueing, and worker callback behavior. |
| components/thread_pool/include/thread_pool.hpp | Public API, configuration, and documentation/comments for ThreadPool. |
| components/thread_pool/README.md | Component-level README and feature list. |
| components/thread_pool/idf_component.yml | Component Manager manifest (metadata, docs URL, dependencies). |
| components/thread_pool/CMakeLists.txt | Registers the component with ESP-IDF build system. |
| components/thread_pool/example/CMakeLists.txt | Example project CMake configuration and component selection. |
| components/thread_pool/example/main/CMakeLists.txt | Registers the example’s main component. |
| components/thread_pool/example/main/thread_pool_example.cpp | Example app demonstrating pool usage and completion waiting. |
| components/thread_pool/example/README.md | Example build/run instructions. |
| components/thread_pool/example/sdkconfig.defaults | Enables C++ exceptions for the example build. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (2)
components/thread_pool/README.md:12
- README claims stop "drains queued jobs", but ThreadPool::stop() explicitly warns that queued jobs may not be executed (and the current implementation can leave queued jobs unprocessed). Please update this feature bullet to match the actual stop semantics so users aren’t misled.
- Graceful stop (stops workers; queued jobs may not be executed)
components/thread_pool/idf_component.yml:8
documentationpoints tocore/thread_pool.html, but there are no correspondingdoc/en/**pages and nodoc/DoxyfileINPUT/EXAMPLE_PATH entries for this new component. This will produce a broken documentation link and omit the API/example from the published docs; please add the required doc pages and Doxyfile entries (kept in alphabetical order) so the link resolves.
documentation: "https://esp-cpp.github.io/espp/core/thread_pool.html"
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
doc/en/core/thread_pool_example.md:3
- The include path looks incorrect relative to
doc/en/core/thread_pool_example.md.../../components/...resolves underdoc/components/..., not<repo_root>/components/.... Update the include path (likely to../../../components/thread_pool/example/README.md) so docs builds can actually find the example README.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (3)
components/thread_pool/src/thread_pool.cpp:60
- Typos/grammar in comments: "thread should stopped" and "heres". These comments are user-facing in the source and should be corrected for clarity.
queue_has_work_cv_.notify_all();
queue_has_space_cv_.notify_all(); // thread should stopped after notify all.
for (auto &worker : workers_) {
worker->stop(); // stop and join heres
}
components/thread_pool/include/thread_pool.hpp:62
- Docstring grammar: "true if at all workers" / "and return true" reads incorrectly and is likely a typo.
/// @brief Start all worker threads.
/// @return true if at all workers were successfully started, false otherwise.
/// @note No-op if the pool is already running and return true immediately.
/// @note If any workers could not be started, the pool will roll back to the stopped state.
components/thread_pool/example/main/thread_pool_example.cpp:136
- This test assumes
max_queue_sizeincludes the currently executing job ("1 executing + 2 queued"), but the implementation enforces the queue size only. As written, the first 3try_submit()calls can be nondeterministically rejected depending on whether the worker has dequeued the first job yet.
// 1 slow worker, capacity 2: 1 executing + 2 queued = 3 slots before rejection
espp::ThreadPool pool({
.worker_count = 1,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (1)
doc/en/core/thread_pool_example.md:3
- The MyST
{include}directive must start at column 0, otherwise Sphinx may treat it as a code block and the include won’t execute. Remove the leading indentation so the directive is parsed correctly.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
components/thread_pool/src/thread_pool.cpp:44
- The warning message in start() is overly specific ("insufficient memory"), but Task::start() can also fail for other reasons (e.g., invalid core_id or too-small stack). This can mislead debugging; use a more general reason in the log message.
if ((!workers_[i]->start()) && (!workers_[i]->is_running())) {
logger_.warn("Failed to start worker {} (already started or insufficient memory)", i);
components/thread_pool/src/thread_pool.cpp:60
- The inline comments here contain typos and are also a bit misleading (notify_all() does not itself stop threads). Clarify the intent so future changes don’t accidentally reorder the notify/stop sequence incorrectly.
queue_has_space_cv_.notify_all(); // thread should stopped after notify all.
for (auto &worker : workers_) {
worker->stop(); // stop and join heres
}
components/thread_pool/example/main/thread_pool_example.cpp:18
- wait_for_jobs() uses std::condition_variable with an atomic predicate that is updated without holding the associated mutex. This can miss the final notification (lost wakeup) and block forever. Using a timed wait loop avoids deadlock without having to restructure all the producer-side increments.
static void wait_for_jobs(std::condition_variable &cv, std::mutex &mtx, std::atomic<int> &completed,
int expected) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&]() { return completed.load() >= expected; });
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
components/thread_pool/include/thread_pool.hpp:35
Stats::rejectedcurrently documents both rejected submissions and jobs dropped from the queue duringstop(), which makes the meaning ambiguous for API consumers reading the counters. Clarify thatrejectedincludes both rejected submissions and dropped queued jobs on stop (or consider splitting into separate counters, but at least document it clearly).
struct Stats {
std::uint64_t submitted = 0; ///< Total jobs accepted into the queue.
std::uint64_t executed = 0; ///< Total jobs successfully executed.
std::uint64_t rejected = 0; ///< Total jobs rejected (invalid job, stopped/stopping, or queue full) or dropped (due to stop, the enqueued jobs were dropped).
};
components/thread_pool/include/thread_pool.hpp:43
block_on_submit_when_full=truecan deadlock ifsubmit()is called from within a worker job on a bounded queue (e.g., worker_count==1 and queue full, or all workers block trying to submit). Please add an explicit warning in the config field docs so users know to prefertry_submit()(or an unbounded queue) from within jobs.
std::size_t max_queue_size = 0; ///< Maximum pending jobs (0 = unbounded).
bool auto_start = true; ///< Start workers immediately on construction.
bool block_on_submit_when_full = false; ///< If true, submit() blocks when the queue is full instead of rejecting.
espp::Task::BaseConfig worker_task_config = { ///< Base configuration applied to every worker task.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
doc/en/core/thread_pool_example.md:3
- The include path looks incorrect relative to
doc/en/core/thread_pool_example.md. Fromdoc/en/core/,../../components/...resolves todoc/components/...(likely non-existent). Adjust the relative path so it resolves to the repository rootcomponents/thread_pool/example/README.md(e.g.,../../../components/thread_pool/example/README.md) to prevent the docs build from failing.
…running and remove mutex
finger563
left a comment
There was a problem hiding this comment.
Looking good, thanks for making this component! A minor update I might suggest is that the first / primary code snippet / example code for the class should be standard use (not one of the tests) so that it's easier for others to read / follow how they should expect to use it and it's easier for them to copy into their code as a starting point. For that purpose, I might suggest adding another section in the example which is simple use showing with straightforward code, and that section is the first snippet / example in the docstring.
Description
add Thread_pool component
Motivation and Context
A thread pool that dispatches submitted jobs to a fixed set of worker threads.
How has this been tested?
an example is added and tested.
The example was tested on an esp32 board. it use a thread_pool with 2 works and finished 8 jobs.
Screenshots (if appropriate, e.g. schematic, board, console logs, lab pictures):
Types of changes
Checklist:
Software
.github/workflows/build.ymlfile to add my new test to the automated cloud build github action.Hardware