[exec.run.loop] (original) (raw)
33 Execution control library [exec]
33.12 Execution contexts [exec.ctx]
33.12.1 execution::run_loop [exec.run.loop]
33.12.1.1 General [exec.run.loop.general]
A run_loop is an execution resource on which work can be scheduled.
It maintains a thread-safe first-in-first-out queue of work.
Its run member function removes elements from the queue and executes them in a loop on the thread of execution that calls run.
A run_loop instance has an associated countthat corresponds to the number of work items that are in its queue.
Additionally, a run_loop instance has an associated state that can be one ofstarting, running, finishing, or finished.
Concurrent invocations of the member functions of run_loopother than run and its destructor do not introduce data races.
The member functions_pop-front_, push-back, and finishexecute atomically.
Recommended practice: Implementations should use an intrusive queue of operation states to hold the work units to make scheduling allocation-free.
namespace std::execution { class run_loop { class run-loop-scheduler; class run-loop-sender; struct run-loop-opstate-base { virtual void execute() = 0; run_loop* loop; run-loop-opstate-base* next; };template<class Rcvr> using run-loop-opstate = unspecified; run-loop-opstate-base* pop-front(); void push-back(run-loop-opstate-base*); public: run_loop() noexcept; run_loop(run_loop&&) = delete;~run_loop();run-loop-scheduler get_scheduler();void run();void finish();};}
33.12.1.2 Associated types [exec.run.loop.types]
class _run-loop-scheduler_;
run-loop-scheduler is an unspecified type that models scheduler.
Instances of run-loop-scheduler remain valid until the end of the lifetime of the run_loop instance from which they were obtained.
Two instances of run-loop-scheduler compare equal if and only if they were obtained from the same run_loop instance.
Let sch be an expression of type run-loop-scheduler.
The expression schedule(sch)has type run-loop- sender and is not potentially-throwing if sch is not potentially-throwing.
run-loop-sender is an exposition-only type that satisfies sender.
For any type Env,completion_signatures_of_t<_run-loop-sender_, Env> iscompletion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>
An instance of run-loop-sender remains valid until the end of the lifetime of its associated run_loop instance.
Let sndr be an expression of type run-loop-sender, let rcvr be an expression such that receiver_of<decltype((_rcvr_)), CS> is truewhere CS is the completion_signatures specialization above.
Let C be either set_value_t or set_stopped_t.
Then:
- The expression connect(sndr, rcvr)has type run-loop-opstate<decay_t<decltype((_rcvr_))>>and is potentially-throwing if and only if(void(sndr), auto(rcvr)) is potentially-throwing.
- The expression get_completion_scheduler<C>(get_env(sndr))is potentially-throwing if and only if sndr is potentially-throwing, has type run-loop-scheduler, and compares equal to the run-loop-
scheduler instance from which sndr was obtained.
template<class Rcvr> struct _run-loop-opstate_;
run-loop-opstate<Rcvr>inherits privately and unambiguously from run-loop-opstate-base.
Let o be a non-const lvalue of type run-loop-opstate<Rcvr>, and let REC(o) be a non-const lvalue reference to an instance of type Rcvrthat was initialized with the expression _rcvr_passed to the invocation of connect that returned o.
Then:
- The object to which REC(o) refers remains valid for the lifetime of the object to which o refers.
- The type run-loop-opstate<Rcvr> overrides_run-loop-opstate-base_::execute()such that o.execute() is equivalent to:if (get_stop_token(REC(o)).stop_requested()) { set_stopped(std::move(REC(o)));} else { set_value(std::move(REC(o)));}
- The expression start(o) is equivalent to:try { o._loop_->push-back(addressof(o));} catch(...) { set_error(std::move(REC(o)), current_exception());}
33.12.1.3 Constructor and destructor [exec.run.loop.ctor]
Postconditions: count is 0 and state is starting.
Effects: If count is not 0 or if state is running, invokes terminate ([except.terminate]).
Otherwise, has no effects.
33.12.1.4 Member functions [exec.run.loop.members]
_run-loop-opstate-base_* _pop-front_();
Effects: Blocks ([defns.block]) until one of the following conditions is true:
- count is 0 and state is finishing, in which case pop-front sets state to _finished_and returns nullptr; or
- count is greater than 0, in which case an item is removed from the front of the queue,count is decremented by 1, and the removed item is returned.
void _push-back_(_run-loop-opstate-base_* item);
Effects: Adds item to the back of the queue and increments count by 1.
Synchronization: This operation synchronizes with the pop-front operation that obtains item.
_run-loop-scheduler_ get_scheduler();
Returns: An instance of _run-loop-scheduler_that can be used to schedule work onto this run_loop instance.
Preconditions: state is either starting or finishing.
Effects: If state is starting, sets the state to running, otherwise leaves state unchanged.
Then, equivalent to:while (auto* op = pop-front()) { op->execute();}
Remarks: When state changes, it does so without introducing data races.
Preconditions: state is either starting or running.
Effects: Changes state to finishing.
Synchronization: finish synchronizes with the pop-front operation that returns nullptr.