Skip to content

Commit 08a5879

Browse files
committed
Fix exec::thread_pool_base customization of bulk_unchunked and correctly handle non-parallel execution policies
1 parent f91f636 commit 08a5879

1 file changed

Lines changed: 58 additions & 14 deletions

File tree

include/exec/thread_pool_base.hpp

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import stdexec;
2828
#else
2929
# include "../stdexec/__detail/__execution_fwd.hpp"
3030

31+
# include "../stdexec/__detail/__bulk.hpp"
3132
# include "../stdexec/__detail/__connect.hpp"
3233
# include "../stdexec/__detail/__env.hpp"
3334
# include "../stdexec/__detail/__meta.hpp"
@@ -81,7 +82,9 @@ namespace experimental::execution
8182

8283
struct domain : STDEXEC::default_domain
8384
{
84-
template <sender_for<STDEXEC::bulk_chunked_t> Sender, class Env>
85+
template <class Sender, class Env>
86+
requires sender_for<Sender, STDEXEC::bulk_chunked_t>
87+
|| sender_for<Sender, STDEXEC::bulk_unchunked_t>
8588
static constexpr auto transform_sender(STDEXEC::set_value_t, Sender&& sndr, Env const & env)
8689
{
8790
auto& [tag, data, child] = sndr;
@@ -91,12 +94,33 @@ namespace experimental::execution
9194
{
9295
auto sch =
9396
STDEXEC::get_completion_scheduler<STDEXEC::set_value_t>(STDEXEC::get_env(child), env);
94-
using sender_t =
95-
scheduler::template bulk_sender_t<decltype(child), decltype(shape), decltype(fun)>;
96-
return sender_t{*sch.pool_,
97-
STDEXEC::__forward_like<Sender>(child),
98-
shape,
99-
STDEXEC::__forward_like<Sender>(fun)};
97+
98+
using policy_type = STDEXEC::__decay_t<decltype(pol.__get())>;
99+
constexpr bool parallelize =
100+
STDEXEC::__same_as<policy_type, STDEXEC::parallel_policy>
101+
|| STDEXEC::__same_as<policy_type, STDEXEC::parallel_unsequenced_policy>;
102+
103+
if constexpr (sender_for<Sender, STDEXEC::bulk_chunked_t>)
104+
{
105+
using sender_t =
106+
scheduler::template bulk_sender_t<decltype(child), decltype(shape), decltype(fun)>;
107+
return sender_t{*sch.pool_,
108+
STDEXEC::__forward_like<Sender>(child),
109+
shape,
110+
STDEXEC::__forward_like<Sender>(fun),
111+
parallelize};
112+
}
113+
else
114+
{
115+
using fun_t = STDEXEC::__bulk::__as_bulk_chunked_fn<STDEXEC::__decay_t<decltype(fun)>>;
116+
using sender_t =
117+
scheduler::template bulk_sender_t<decltype(child), decltype(shape), fun_t>;
118+
return sender_t{*sch.pool_,
119+
STDEXEC::__forward_like<Sender>(child),
120+
shape,
121+
fun_t{STDEXEC::__forward_like<Sender>(fun)},
122+
parallelize};
123+
}
100124
}
101125
else
102126
{
@@ -110,9 +134,6 @@ namespace experimental::execution
110134
STDEXEC::_WITH_ENVIRONMENT_(Env)>();
111135
}
112136
}
113-
114-
template <sender_for<STDEXEC::bulk_unchunked_t> Sender, class Env>
115-
static constexpr auto transform_sender(STDEXEC::set_value_t, Sender&& sndr, Env const & env);
116137
};
117138

118139
struct scheduler
@@ -197,6 +218,7 @@ namespace experimental::execution
197218
Receiver rcvr_;
198219
Shape shape_;
199220
Fun fun_;
221+
bool parallelize_;
200222

201223
std::atomic<std::uint32_t> finished_threads_{0};
202224
std::atomic<std::uint32_t> thread_with_exception_{0};
@@ -205,6 +227,11 @@ namespace experimental::execution
205227
[[nodiscard]]
206228
auto num_agents_required() const -> std::uint32_t
207229
{
230+
if (!parallelize_)
231+
{
232+
return 1;
233+
}
234+
208235
// With work stealing, is std::min necessary, or can we feel free to ask for more agents (tasks)
209236
// than we can actually deal with at one time?
210237
return static_cast<std::uint32_t>(
@@ -219,11 +246,16 @@ namespace experimental::execution
219246
data_);
220247
}
221248

222-
explicit bulk_shared_state(DerivedPoolType& pool, Receiver rcvr, Shape shape, Fun fun)
249+
explicit bulk_shared_state(DerivedPoolType& pool,
250+
Receiver rcvr,
251+
Shape shape,
252+
Fun fun,
253+
bool parallelize)
223254
: pool_(pool)
224255
, rcvr_{static_cast<Receiver&&>(rcvr)}
225256
, shape_{shape}
226257
, fun_{fun}
258+
, parallelize_{parallelize}
227259
, thread_with_exception_{num_agents_required()}
228260
{
229261
this->execute_ = [](_pool_::task_base* t, std::uint32_t tid) noexcept
@@ -379,8 +411,13 @@ namespace experimental::execution
379411
STDEXEC::start(inner_op_);
380412
}
381413

382-
bulk_opstate(DerivedPoolType& pool, Shape shape, Fun fun, CvSender&& sndr, Receiver rcvr)
383-
: shared_state_(pool, static_cast<Receiver&&>(rcvr), shape, fun)
414+
bulk_opstate(DerivedPoolType& pool,
415+
Shape shape,
416+
Fun fun,
417+
bool parallelize,
418+
CvSender&& sndr,
419+
Receiver rcvr)
420+
: shared_state_(pool, static_cast<Receiver&&>(rcvr), shape, fun, parallelize)
384421
, inner_op_{STDEXEC::connect(static_cast<CvSender&&>(sndr), bulk_rcvr{shared_state_})}
385422
{}
386423

@@ -414,11 +451,16 @@ namespace experimental::execution
414451
using bulk_opstate_t =
415452
bulk_opstate<STDEXEC::__copy_cvref_t<Self, Sender>, Receiver, Shape, Fun>;
416453

417-
explicit bulk_sender(DerivedPoolType& pool, Sender sndr, Shape shape, Fun fun)
454+
explicit bulk_sender(DerivedPoolType& pool,
455+
Sender sndr,
456+
Shape shape,
457+
Fun fun,
458+
bool parallelize)
418459
: pool_(pool)
419460
, sndr_(std::move(sndr))
420461
, shape_(shape)
421462
, fun_(std::move(fun))
463+
, parallelize_(parallelize)
422464
{}
423465

424466
template <STDEXEC::__decays_to<bulk_sender> Self, STDEXEC::receiver Receiver>
@@ -436,6 +478,7 @@ namespace experimental::execution
436478
return bulk_opstate_t<Self, Receiver>{self.pool_,
437479
self.shape_,
438480
static_cast<Self&&>(self).fun_,
481+
self.parallelize_,
439482
static_cast<Self&&>(self).sndr_,
440483
static_cast<Receiver&&>(rcvr)};
441484
}
@@ -473,6 +516,7 @@ namespace experimental::execution
473516
Sender sndr_;
474517
Shape shape_;
475518
Fun fun_;
519+
bool parallelize_;
476520
};
477521

478522
template <STDEXEC::sender Sender, std::integral Shape, class Fun>

0 commit comments

Comments
 (0)