Skip to content

Commit dbbd056

Browse files
committed
P3927R2 task_scheduler support for parallel bulk execution
Fixes NB US 238-368 (C++26 CD).
1 parent 6837212 commit dbbd056

File tree

1 file changed

+170
-60
lines changed

1 file changed

+170
-60
lines changed

source/exec.tex

Lines changed: 170 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7029,10 +7029,10 @@
70297029
\begin{codeblock}
70307030
namespace std::execution {
70317031
class @\libglobal{task_scheduler}@ {
7032-
class @\exposidnc{ts-sender}@; // \expos
7032+
class @\exposidnc{ts-domain}@; // \expos
70337033

7034-
template<@\libconcept{receiver}@ R>
7035-
class @\exposidnc{state}@; // \expos
7034+
template<@\libconcept{scheduler}@ Sch>
7035+
class @\exposid{backend-for}@; // \expos
70367036

70377037
public:
70387038
using scheduler_concept = scheduler_t;
@@ -7045,7 +7045,7 @@
70457045
task_scheduler(const task_scheduler&) = default;
70467046
task_scheduler& operator=(const task_scheduler&) = default;
70477047

7048-
@\exposid{ts-sender}@ schedule();
7048+
@\seebelow@ schedule();
70497049

70507050
friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs)
70517051
noexcept;
@@ -7055,7 +7055,7 @@
70557055
friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
70567056

70577057
private:
7058-
shared_ptr<void> @\exposidnc{sch_}@; // \expos
7058+
shared_ptr<system_context_replaceability::parallel_scheduler_backend> @\exposidnc{sch_}@; // \expos; see \ref{exec.sysctxrepl.psb}
70597059
};
70607060
}
70617061
\end{codeblock}
@@ -7066,6 +7066,10 @@
70667066
Given an object \tcode{s} of type \tcode{task_scheduler}, let
70677067
\tcode{\exposid{SCHED}(s)} be the object
70687068
pointed to by the pointer owned by \tcode{s.\exposid{sch_}}.
7069+
The expression \tcode{get_forward_progress_guarantee(s)} is equivalent to
7070+
\tcode{get_forward_progress_guarantee(SCHED(s))}.
7071+
The expression \tcode{get_completion_domain<set_value_t>(s)} is equivalent to
7072+
\tcode{task_scheduler::ts-domain()}.
70697073

70707074
\indexlibraryctor{task_scheduler}
70717075
\begin{itemdecl}
@@ -7077,7 +7081,7 @@
70777081
\pnum
70787082
\effects
70797083
Initialize \exposid{sch_} with
7080-
\tcode{allocate_shared<remove_cvref_t<Sch>>(alloc,\brk{} std::forward<Sch>\brk{}(sch))}.
7084+
\tcode{allocate_shared<\exposid{backend-for}<remove_cvref_t<Sch>>>(alloc, std::forward<Sch>(sch))}.
70817085

70827086
\pnum
70837087
\recommended
@@ -7086,22 +7090,10 @@
70867090

70877091
\pnum
70887092
\remarks
7089-
Any allocations performed by construction of \exposid{ts-sender} or
7090-
\exposid{state} objects resulting from calls on \tcode{*this} are
7093+
Any allocations performed by calls on \tcode{*this} are
70917094
performed using a copy of \tcode{alloc}.
70927095
\end{itemdescr}
70937096

7094-
\indexlibrarymember{scheduler}{task_scheduler}%
7095-
\begin{itemdecl}
7096-
@\exposid{ts-sender}@ schedule();
7097-
\end{itemdecl}
7098-
\begin{itemdescr}
7099-
\pnum
7100-
\effects
7101-
Returns an object of type \exposid{ts-sender} containing a sender
7102-
initialized with \tcode{sched\-ule(\brk{}\exposid{SCHED}\brk{}(*this))}.
7103-
\end{itemdescr}
7104-
71057097
\indexlibrarymember{operator==}{task_scheduler}%
71067098
\begin{itemdecl}
71077099
bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
@@ -7127,77 +7119,195 @@
71277119
\end{itemdescr}
71287120

71297121
\pnum
7122+
For an lvalue \tcode{r} of a type derived from \tcode{receiver_proxy},
7123+
let \tcode{\exposid{WRAP-RCVR}(r)}x be an object of a type
7124+
that models \libconcept{receiver} and
7125+
whose completion handlers result in
7126+
invoking the corresponding completion handlers of \tcode{r}.
71307127
\begin{codeblock}
71317128
namespace std::execution {
7132-
class task_scheduler::@\exposidnc{ts-sender}@ { // \expos
7129+
template<@\libconcept{scheduler}@ Sch>
7130+
class task_scheduler::@\exposid{backend-for}@
7131+
: public system_context_replaceability::parallel_scheduler_backend { // \expos
71337132
public:
7134-
using sender_concept = sender_t;
7133+
explicit @\exposid{backend-for}@(Sch sch) : @\exposid{sched_}@(std::move(sch)) {}
71357134

7136-
template<@\libconcept{receiver}@ Rcvr>
7137-
@\exposid{state}@<Rcvr> connect(Rcvr&& rcvr) &&;
7135+
void schedule(receiver_proxy& r, span<byte> s) noexcept override;
7136+
void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r,
7137+
span<byte> s) noexcept override;
7138+
void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r,
7139+
span<byte> s) noexcept override;
7140+
7141+
private:
7142+
Sch @\exposid{sched_}@;
71387143
};
71397144
}
71407145
\end{codeblock}
7141-
\exposid{ts-sender} is an exposition-only class that models
7142-
\libconcept{sender}\iref{exec.snd} and for which
7143-
\tcode{completion_signatures_of_t<\exposid{ts-sender}>} denotes:
7144-
\begin{codeblock}
7145-
completion_signatures<
7146-
set_value_t(),
7147-
set_error_t(error_code),
7148-
set_error_t(exception_ptr),
7149-
set_stopped_t()>
7150-
\end{codeblock}
71517146

71527147
\pnum
7153-
Let \tcode{\placeholder{sch}} be an object of type \tcode{task_scheduler}
7154-
and let \tcode{sndr} be an object of type \exposid{ts-sender} obtained
7155-
from \tcode{schedule(\placeholder{sch})}.
7156-
Then \tcode{get_completion_scheduler<set_value_t>(get_env(sndr)) == \placeholder{sch}}
7157-
is \tcode{true}.
7158-
The object \tcode{\exposid{SENDER}(sndr)} is the sender object contained by
7159-
\tcode{sndr} or an object move constructed from it.
7148+
Let \tcode{env} be a pack of subexpressions, and
7149+
let \exposid{just-sndr-like} be a sender
7150+
whose only value completion signature is \tcode{set_value_t()} and
7151+
for which the expression
7152+
\tcode{get_completion_scheduler<set_value_t>(get_env(\exposid{just-sndr-like)}, env...)}
7153+
is expression-equivalent to
7154+
\tcode{get_completion_scheduler<set_value_t>(\exposid{sched_}, env...)}.
71607155

7161-
\indexlibrarymember{connect}{task_scheduler::\exposid{ts-sender}}%
71627156
\begin{itemdecl}
7163-
template<@\libconcept{receiver}@ Rcvr>
7164-
@\exposid{state}@<Rcvr> connect(Rcvr&& rcvr) &&;
7157+
void schedule(receiver_proxy& r, span<byte> s) noexcept override;
7158+
\end{itemdecl}
7159+
7160+
\begin{itemdescr}
7161+
\pnum
7162+
\effects
7163+
Constructs an operation state \tcode{os}
7164+
with \tcode{connect(schedule(\exposid{sched_}), \exposid{WRAP-RCVR}(r))} and
7165+
calls \tcode{start(os)}.
7166+
\end{itemdescr}
7167+
7168+
\begin{itemdecl}
7169+
void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r,
7170+
span<byte> s) noexcept override;
7171+
\end{itemdecl}
7172+
7173+
\begin{itemdescr}
7174+
\pnum
7175+
\effects
7176+
Let \tcode{chunk_size} be an integer less than or equal to \tcode{shape},
7177+
let \tcode{num_chunks} be \tcode{(shape + chunk_size - 1) / chunk_size}, and
7178+
let \tcode{fn} be a function object such that
7179+
for an integer \tcode{i},
7180+
\tcode{fn(i)} calls \tcode{r.execute(i * chunk_size, m)},
7181+
where \tcode{m} is the lesser of \tcode{(i + 1) * chunk_size} and \tcode{shape}.
7182+
Constructs an operation state \tcode{os} as if with
7183+
\begin{codeblock}
7184+
connect(bulk(@\exposid{just-sndr-like}@, par, num_chunks, fn), @\exposid{WRAP-RCVR}@(r))
7185+
\end{codeblock}
7186+
and calls \tcode{start(os)}.
7187+
\end{itemdescr}
7188+
7189+
\begin{itemdecl}
7190+
void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r,
7191+
span<byte> s) noexcept override;
71657192
\end{itemdecl}
7193+
71667194
\begin{itemdescr}
71677195
\pnum
71687196
\effects
7169-
Let \tcode{\placeholder{r}} be an object of a type that models \libconcept{receiver}
7170-
and whose completion handlers result in invoking the corresponding
7171-
completion handlers of \tcode{rcvr} or copy thereof.
7172-
Returns an object of type \tcode{\exposid{state}<Rcvr>} containing
7173-
an operation state object initialized with \tcode{connect(\exposid{SENDER}(*this),
7174-
std::move(\placeholder{r}))}.
7197+
Let \tcode{fn} be a function object such that
7198+
for an integer \tcode{i},
7199+
\tcode{fn(i)} is equivalent to \tcode{r.execute(i, i + 1)}.
7200+
Constructs an operation state \tcode{os} as if with
7201+
\tcode{connect(bulk(\exposid{just-sndr-like}, par, shape, fn), \exposid{WRAP-RCVR}(r))}
7202+
and calls \tcode{start(os)}.
71757203
\end{itemdescr}
71767204

7205+
\begin{itemdecl}
7206+
@\seebelow@ schedule();
7207+
\end{itemdecl}
7208+
7209+
\begin{itemdescr}
71777210
\pnum
7211+
\returns
7212+
A prvalue \exposid{ts-sndr} whose type models \libconcept{sender} such that:
7213+
\begin{itemize}
7214+
\item
7215+
\tcode{get_completion_scheduler<set_value_t>(get_env(\exposid{ts-sndr}))}
7216+
is equal to \tcode{*this.}
7217+
\item
7218+
\tcode{get_completion_domain<set_value_t>(get_env(\exposid{ts-sndr}))}
7219+
is expression-equivalent to \tcode{\exposid{ts-domain}()}.
7220+
\item
7221+
If a receiver \tcode{rcvr} is connected to \exposid{ts-sndr} and
7222+
the resulting operation state is started,
7223+
calls \tcode{\exposid{sch_}->schedule(r, s)}, where
7224+
\begin{itemize}
7225+
\item
7226+
\tcode{r} is a proxy for \tcode{rcvr} with base
7227+
\tcode{system_context_replaceability::eceiver_proxy}\iref{exec.par.scheduler}
7228+
and
7229+
\item
7230+
\tcode{s} is a preallocated backend storage for \tcode{r}.
7231+
\end{itemize}
7232+
\item
7233+
For any type \tcode{E},
7234+
\tcode{completion_signatures_of_t<decltype(\exposid{ts-sndr}), E>} denotes
7235+
\tcode{completion_signatures<set_value_t()>} if
7236+
\tcode{\libconcept{unstoppable_token}<stop_token_of_t<E>>} is \tcode{true}, and
7237+
otherwise \tcode{completion_signatures<set_value_t(), set_stopped_t()>}.
7238+
\end{itemize}
7239+
\end{itemdescr}
7240+
71787241
\begin{codeblock}
71797242
namespace std::execution {
7180-
template<@\libconcept{receiver}@ R>
7181-
class task_scheduler::@\exposidnc{state}@ { // \expos
7243+
class task_scheduler::@\exposid{ts-domain}@ : public default_domain { // \expos
71827244
public:
7183-
using operation_state_concept = operation_state_t;
7184-
7185-
void start() & noexcept;
7245+
template<class BulkSndr, class Env>
7246+
static constexpr auto transform_sender(set_value_t, BulkSndr&& bulk_sndr, const Env& env)
7247+
noexcept(@\seebelow@);
71867248
};
71877249
}
71887250
\end{codeblock}
7189-
\exposid{state} is an exposition-only class template whose
7190-
specializations model \libconcept{operation_state}\iref{exec.opstate}.
71917251

7192-
\indexlibrarymember{start}{task_scheduler::\exposid{state}}%
71937252
\begin{itemdecl}
7194-
void start() & noexcept;
7253+
template<class BulkSndr, class Env>
7254+
static constexpr auto transform_sender(BulkSndr&& bulk_sndr, const Env& env)
7255+
noexcept(is_nothrow_constructible_v<decay_t<BulkSndr>, BulkSndr>);
71957256
\end{itemdecl}
7257+
71967258
\begin{itemdescr}
7259+
\pnum
7260+
\constraints
7261+
\begin{itemize}
7262+
\item
7263+
\tcode{\libconcept{sender_in}<BulkSndr, Env>} is \tcode{true},
7264+
\item
7265+
\tcode{auto(std::forward<BulkSndr>(bulk_sndr))} is well-formed, and
7266+
either \tcode{\exposconcept{sender-for}<BulkSndr, bulk_chunked_t>} or
7267+
\exposconcept{sender-for}<BulkSndr, bulk_unchunked_t> is \tcode{true}.
7268+
\end{itemize}
7269+
71977270
\pnum
71987271
\effects
7199-
Equivalent to \tcode{start(st)} where \tcode{st} is the operation
7200-
state object contained by \tcode{*this}.
7272+
Equivalent to:
7273+
\begin{codeblock}
7274+
auto& [_, data, child] = bulk_sndr;
7275+
auto& [_, shape, fn] = data;
7276+
auto sch = @\exposid{call-with-default}@(get_completion_scheduler<set_value_t>,
7277+
@\exposid{not-a-scheduler}@(), get_env(child), @\exposid{FWD-ENV}@(env));
7278+
return @$e$@;
7279+
\end{codeblock}
7280+
where $e$ is \tcode{\exposid{not-a-sender}()}
7281+
if the type of \tcode{sch} is not \tcode{task_scheduler};
7282+
otherwise, it is a prvalue whose type models \libconcept{sender} such that,
7283+
if it is connected to a receiver \tcode{rcvr} and
7284+
the resulting operation state is started,
7285+
\tcode{child} is connected to an unspecified receiver \tcode{R} and started.
7286+
The expression \tcode{get_env(R)}
7287+
is expression-equivalent to \tcode{\exposid{FWD-ENV}(get_env(\exposid{rcvr-copy}))},
7288+
where \exposid{rcvr-copy} is an lvalue subexpression
7289+
designating an object decay-copied from \tcode{rcvr}.
7290+
7291+
If \tcode{child} completes with an error or a stopped completion,
7292+
the completion operation is forwarded unchanged to \tcode{rcvr}.
7293+
Otherwise, let \tcode{args} be a pack of lvalue subexpressions
7294+
designating objects decay-copied from the value result datums.
7295+
Then:
7296+
\begin{itemize}
7297+
\item
7298+
If \tcode{bulk_sndr} was the result of the evaluation of
7299+
an expression equivalent to \tcode{bulk_chunked(child, policy, shape, fn)} or
7300+
a copy of such,
7301+
then \tcode{\exposid{sch_}->schedule_bulk_chunked(shape, r, s)} is called
7302+
where \tcode{r} is a bulk chunked proxy\iref{exec.par.scheduler}
7303+
for \tcode{rcvr} with callable \tcode{fn} and arguments \tcode{args}, and
7304+
\tcode{s} is a preallocated backend storage for \tcode{r}.
7305+
\item
7306+
Otherwise, calls \tcode{\exposid{sch_}->schedule_bulk_unchunked(shape, r, s)}
7307+
where \tcode{r} is a bulk unchunked proxy for \tcode{rcvr}
7308+
with callable \tcode{fn} and arguments \tcode{args}, and
7309+
\tcode{s} is a preallocated backend storage for \tcode{r}.
7310+
\end{itemize}
72017311
\end{itemdescr}
72027312

72037313
\rSec2[exec.task]{\tcode{execution::task}}

0 commit comments

Comments
 (0)