Skip to content

threadpool: add ranged Submit overload#34576

Merged
sedited merged 1 commit intobitcoin:masterfrom
andrewtoth:threadpool_submitmany
Mar 11, 2026
Merged

threadpool: add ranged Submit overload#34576
sedited merged 1 commit intobitcoin:masterfrom
andrewtoth:threadpool_submitmany

Conversation

@andrewtoth
Copy link
Contributor

@andrewtoth andrewtoth commented Feb 12, 2026

The current ThreadPool::Submit is not very efficient when we have a use case where we need to submit multiple tasks immediately. The Submit method must take the lock for each task, and notifies only a single worker thread. This will cause lock contention with the awakened worker thread trying to take the lock and the caller trying to submit the next task.

Introduce a Submit overload, which takes the lock once and submits a range of tasks, then notifies all worker threads after the lock is released.

This is needed for #31132 to be able to use ThreadPool.

@DrahtBot
Copy link
Contributor

DrahtBot commented Feb 12, 2026

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK l0rinc, sedited, willcl-ark, rkrux
Stale ACK sipa, furszy

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #31132 (validation: fetch block inputs on parallel threads 3x faster IBD by andrewtoth)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

* uncaught exceptions, as they would otherwise be silently discarded.
*/
template <class F>
[[nodiscard]] util::Expected<std::vector<std::future<std::invoke_result_t<F>>>, SubmitError> SubmitMany(std::vector<F>&& fns) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General question to think about (no need to answer here):

Is there any use-case for submitting callables with different return types? Because if there is, then we are forced to use a variadic-based approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a new overload if the need arises?

@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch 2 times, most recently from cdecfa7 to 1593245 Compare February 20, 2026 03:32
@andrewtoth
Copy link
Contributor Author

Thanks @furszy and @willcl-ark. Taken your suggestions and rebased.

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 3295552

Copy link
Member

@sipa sipa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK 3295552

@andrewtoth andrewtoth changed the title threadpool: add SubmitMany threadpool: add ranged Submit overload Feb 22, 2026
@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch from 3295552 to 43c5c77 Compare February 28, 2026 00:17
@andrewtoth
Copy link
Contributor Author

andrewtoth commented Feb 28, 2026

Rebased due to #34562. Addressed nit (#34576 (comment)). Reworded commit message. Only test changes since last push.

git range-diff 739f75c0980ef30f676183323f4cb41fb9272b71..3295552c0a895fa650c0e0c67600c384fdbcde50 9cad97f6cdf1bd660732cd10e844a6a7e0771ea0..43c5c77fcb6f68fee5249c3b8666cd86dd1c9038

@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch from 43c5c77 to fdddacc Compare February 28, 2026 15:51
Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK fdddacc

@DrahtBot DrahtBot requested a review from sipa February 28, 2026 16:00
Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple points in the test.

@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch from fdddacc to 2852489 Compare March 7, 2026 15:10
@andrewtoth
Copy link
Contributor Author

Thanks for the review @rkrux. I took your suggestions. Test only changes style changes.

git diff fdddaccc8c9cbd241ad44100e68d49e7bebd0bc4..2852489f4878d3de0e72de77367fae845543ec4c

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK 2852489

Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm ACK 2852489

Thanks for accepting the suggestions.

Copy link
Contributor

@sedited sedited left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 2852489

Can you fix the include order and some of the formatting issues as reported by clang-format-diff?

I also fuzzed this a bit with the following patch, but quickly stoppped finding new coverage:

Click to expand diff
diff --git a/src/test/fuzz/threadpool.cpp b/src/test/fuzz/threadpool.cpp
index a5b01db138..59e2f1b7a8 100644
--- a/src/test/fuzz/threadpool.cpp
+++ b/src/test/fuzz/threadpool.cpp
@@ -72 +72 @@ FUZZ_TARGET(threadpool, .init = setup_threadpool_test) EXCLUSIVE_LOCKS_REQUIRED(
-    const uint32_t num_tasks = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, 1024);
+    uint32_t num_tasks = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, 1024);
@@ -85,0 +86,25 @@ FUZZ_TARGET(threadpool, .init = setup_threadpool_test) EXCLUSIVE_LOCKS_REQUIRED(
+        const bool submit_batch = fuzzed_data_provider.ConsumeBool();
+
+        if (submit_batch) {
+            const uint32_t batch_size = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, 100);
+            i += batch_size;
+            if (will_throw) {
+                expected_fail_tasks += batch_size;
+                auto batch_futures = *Assert(g_pool.Submit(std::vector<ThrowTask>(batch_size)));
+                for (auto& batch_future : batch_futures) {
+                    futures.emplace(std::move(batch_future));
+                }
+            } else {
+                std::vector<CounterTask> tasks;
+                tasks.reserve(batch_size);
+                for (uint32_t j = 0; j < batch_size; ++j) {
+                    expected_task_counter++;
+                    tasks.emplace_back(task_counter);
+                }
+                auto batch_futures = *Assert(g_pool.Submit(std::move(tasks)));
+                for (auto& batch_future : batch_futures) {
+                    futures.emplace(std::move(batch_future));
+                }
+            }
+            continue;
+        }

@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch from 2852489 to e62bfc2 Compare March 10, 2026 00:59
@andrewtoth-exo
Copy link

Thanks for the review and for fuzzing @sedited. I pushed the formatting changes.

git diff 2852489f4878d3de0e72de77367fae845543ec4c..e62bfc241e90b60424365924f676ea85755ae935

Copy link
Contributor

@sedited sedited left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-ACK e62bfc2

@DrahtBot DrahtBot requested review from furszy and rkrux March 10, 2026 07:40
Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK e62bfc2

git range-diff 2852489...e62bfc2

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK e62bfc2

@fanquake fanquake added this to the 32.0 milestone Mar 10, 2026
Copy link
Contributor

@l0rinc l0rinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current version is probably fine, but it seems to me we can make it more accurate by using range reference type instead of the value type - and iterating with auto&& so the overload handles more callable/range shapes correctly. And maybe handle empty with a lockless short-circuit.

LOCK(m_mutex);
if (m_workers.empty()) return util::Unexpected{SubmitError::Inactive};
if (m_interrupt) return util::Unexpected{SubmitError::Interrupted};
for (auto& fn : fns) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e62bfc2 threadpool: add ranged Submit overload:

What should the intended behavior be for an empty fns range?
It might be worth making that explicit and short-circuiting the locking, and maybe covering it with a small test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially did short-circuit it, but it was brought up that it is a behavior change from non-ranged Submit #34576 (comment). I think best to keep behavior identical, so we throw even if fns is empty.

Co-authored-by: l0rinc <pap.lorinc@gmail.com>
@andrewtoth andrewtoth force-pushed the threadpool_submitmany branch from e62bfc2 to 79571b9 Compare March 10, 2026 20:23
@andrewtoth
Copy link
Contributor Author

Thanks for your review @l0rinc. I have taken most of your suggestions.

  • fixed style nit in test
  • changed lvalue to rvalue ref in fns loop
  • added PackagedTask alias
  • updated RangeValueFuture with range_value_t to RangeFuture with range_reference_t
  • fixed style nit in docstring

git diff e62bfc241e90b60424365924f676ea85755ae935..79571b918130e66436b2d43489835c38bb3ae3e3

@l0rinc
Copy link
Contributor

l0rinc commented Mar 10, 2026

ACK 79571b9

Copy link
Contributor

@sedited sedited left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-ACK 79571b9

@DrahtBot DrahtBot requested review from furszy and rkrux March 11, 2026 11:19
Copy link
Member

@willcl-ark willcl-ark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 79571b9

I like the template constraints via requires(), very neat :)

I did not test with e.g. 31132 picked, but the code and tests here look good to me.

@rkrux
Copy link
Contributor

rkrux commented Mar 11, 2026

ACK 79571b9

git range-diff e62bfc2...79571b9

@sedited sedited merged commit 524aa1e into bitcoin:master Mar 11, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.